timezone у пользователя

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

Пытаюсь разобраться с часовыми поясами. Приведу небольшой фрагмент кода

Код: Выделить всё

echo 'Пользователь '.$user->username.' создал аккаунт: '.Yii::$app->formatter->asDateTime($userCreated, 'medium')
        .'<br /> Это было: '.Yii::$app->formatter->asRelativeTime($userCreated, time());
При этом на событие ON_AFTER_REQUEST (ON_BEFORE_REQUEST) навешиваю:

Код: Выделить всё

date_default_timezone_set(Yii::$app->user->identity->time_zone);
Выводит:
Пользователь user создал аккаунт: 15 февр. 2017 г., 3:03:23
Это было: 22 дня назад
Цель: пользователю должна быть показана дата/время регистрации с учетом его часового пояса в профиле.

Вопрос: Я правильно работаю в датой/временем в контексте Yii2 (в данном случае. Я понимаю, что дату рождения нужно хранить в поле типа Date, но интересует именно такой пример)?
Осторожно! Вы общаетесь с новичком ;)
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

лучше выставлять часовой пояс по умолчанию в utc, в бд тоже хранить в utc, а часовой пояс пользователя устанавливать только для форматтера
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

rak писал(а): 2017.03.10, 01:05 лучше выставлять часовой пояс по умолчанию в utc, в бд тоже хранить в utc, а часовой пояс пользователя устанавливать только для форматтера
Спасибо за быстрый ответ. Я не сказал, что сохраняю время time() в поле с типом int. То есть в БД попадает время в UTC, как я понимаю.
Осторожно! Вы общаетесь с новичком ;)
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

girmate писал(а): 2017.03.10, 01:07
rak писал(а): 2017.03.10, 01:05 лучше выставлять часовой пояс по умолчанию в utc, в бд тоже хранить в utc, а часовой пояс пользователя устанавливать только для форматтера
Спасибо за быстрый ответ. Я не сказал, что сохраняю время time() в поле с типом int. То есть в БД попадает время в UTC, как я понимаю.
нет, чтобы time() отдавало в utc нужно делать

Код: Выделить всё

date_default_timezone_set('UTC');
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

более того, в бд тоже может быть настроен свой часовой пояс
так что можно сделать вот так

Код: Выделить всё

'db'  => [
            'class'             => 'yii\db\Connection',
            //...
            'on afterOpen' => function($event) {
                $event->sender->createCommand("SET time_zone = '+0:00'")->execute();
            }
               
        ],
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

Да я вообще запутался. time() возвращает количество секунд...
Я при регистрации пользователя сохраняю это время в поле. Заодно спрашиваю у него часовой пояс, его тоже сохраняю.

Ну а потом через date_default_timezone_set применяю его часовой пояс (ну или только к форматтеру) и показываю результат.
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

И вроде при такой схеме не имеет значение какие там в БД часовые пояса настроены. И правильно ли настроены.
Осторожно! Вы общаетесь с новичком ;)
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

я выше описал рабочую схему, зачем велосипед придумывать?
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

rak писал(а): 2017.03.10, 01:32 я выше описал рабочую схему, зачем велосипед придумывать?
Да вроде Sam Dark тоже хранит дату/время в int. Вот я и примеряю эту схему.
По вашей схеме в каком типе поля должно храниться дата/время?
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

В целом я так и не понял как мне:
1. Сохранять дату/время
2. Показывать пользователю время регистрации с учетом его временой зоны
Последний раз редактировалось girmate 2017.03.10, 10:57, всего редактировалось 1 раз.
Осторожно! Вы общаетесь с новичком ;)
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

1. без разницы как сохранять, главное, чтобы все было в одном часовом поясе(UTC)
2. я уже написал выше
rak писал(а): 2017.03.10, 01:05 лучше выставлять часовой пояс по умолчанию в utc, в бд тоже хранить в utc, а часовой пояс пользователя устанавливать только для форматтера
ну и пользователю выставлять

Код: Выделить всё

Yii::$app->formatter->timeZone = $timezoneFromUserProfile; 
Аватара пользователя
KiTE
Сообщения: 112
Зарегистрирован: 2012.04.12, 14:47

Re: timezone у пользователя

Сообщение KiTE »

rak писал(а): 2017.03.10, 01:10 нет, чтобы time() отдавало в utc нужно делать

Код: Выделить всё

date_default_timezone_set('UTC');
Не вводите в заблуждение.
time() - возвращает текущую временную метку Unix, кол-во секунд с 1970-01-01 00:00:00 GMT, и от date_default_timezone_set() это значение не зависит. От date_default_timezone_set() зависит форматирование с помощью date() или DateTime::format().

Код: Выделить всё

date_default_timezone_set('UTC');
$time1 = time();                     // 1489108454
$date1 = date(DATE_ISO8601, $time1); // 2017-03-10T01:14:14+0000
date_default_timezone_set('Europe/Kiev');
$time2 = time();                     // 1489108454
$date2 = date(DATE_ISO8601, $time2); // 2017-03-10T03:14:14+0200
girmate писал(а): 2017.03.10, 01:39 В целом я так и не понял как мне:
1. Сохранять дату/время
2. Показывать пользователю время регистрациис учетом его временой зоны
В базу дату-время проще всего писать временной меткой как целое число. Не будет двойного преобразования при форматировании. Зону пользователя тоже пишите в БД. То есть:

Код: Выделить всё

$user->created_at = time();
$user->timezone = 'Europe/Kiev';
На запуск приложения повесьте бихейвиор, чтобы зоной по умолчанию сделать зону пользователя:

Код: Выделить всё

Yii::$app->timeZone = $user->timezone; // Внутри там date_default_timezone_set()
На странице форматируйте с помощью:

Код: Выделить всё

Yii::$app->formatter->asDatetime($user->created_at)
Или любым другим способом: date(), DateTime::format(). Это форматирование будет учитывать установленную ранее таймзону по умолчанию.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: timezone у пользователя

Сообщение rak »

KiTE писал(а): 2017.03.10, 04:50 Не вводите в заблуждение.
time() - возвращает текущую временную метку Unix, кол-во секунд с 1970-01-01 00:00:00 GMT, и от date_default_timezone_set() это значение не зависит. От date_default_timezone_set() зависит форматирование с помощью date() или DateTime::format().
да, согласен(начал писать про date(), потому как в БД использую обычно везде datetime) и в последний момент не доглядел :) .
Onotole
Сообщения: 1808
Зарегистрирован: 2012.12.24, 12:49

Re: timezone у пользователя

Сообщение Onotole »

Разве для таймштампа есть разница в часовом поясе? Сохраняется то одно и то же количество секунд, что при +3 что при -12
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

Спасибо огромное KiTE за столь развернутый ответ. Попробовал в действии - вроде все получается.
Вы писали:
KiTE писал(а): 2017.03.10, 04:50 На запуск приложения повесьте бихейвиор, чтобы зоной по умолчанию сделать зону пользователя:

Код: Выделить всё

Yii::$app->timeZone = $user->timezone; // Внутри там date_default_timezone_set()
Я всегда вешал события на до/после request. Запуск приложения это отдельное какое-то событие?
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

KiTE, еще попрошу Вас разъяснить мне один вопрос. С выводом даты/времени вроде разобрались. А как правильно сохранять?

Пользователь из Нью-Йорка поставил в расписание "сходить на ланч в 23:52" (дата в будущем).
Житель из Омска хочет увидеть, что Японец пойдет на ланч по своему местному времени. Допустим, в 13:52 (для примера).

Как правильно это организовать? Какой функцией я должен буду воспользоваться?
Я так понимаю, что Нужно взять дату/время ланча Японца, привести его к времени в UTC (а тут уже нужно учитывать временное смещение японца) и сохранить.
И тогда житель Омска увидит, что Японец собирается на ланч в 13:52.
Последний раз редактировалось girmate 2017.03.10, 16:26, всего редактировалось 1 раз.
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

Я вот думаю что это будет как-то так:

Код: Выделить всё

$date = new DateTime('2017-03-10 23:52');
    echo $date->format('Y.m.d H:i:s'); // выводит 2017.03.10 23:52:00
    echo '<br />';
    echo $date->format('U'); // выводит 1489179120, что соответствует тому же времени, только с учетом часового пояса (Fri, 10 Mar 2017 20:52:00 GMT)
Значит в БД я должен буду положить $date->format('U'); ?

Либо вот еще вариант:

Код: Выделить всё

$date = '2017-03-10 23:52';
    echo  strtotime($date); // выводит 1489179120
И еще:

Код: Выделить всё

Yii::$app->formatter->asTimestamp('2017-03-10 23:52'); // выводит 1489179120
И если я правильно понял, вся эта магия работает благодаря Yii::$app->formatter->timeZone, который я устанавливаю для каждого пользователя свой (из профиля) и этот параметр влияет на все операции с датой/временем, так как знает часовой пояс, в котором находится приложение (пользователь).
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
KiTE
Сообщения: 112
Зарегистрирован: 2012.04.12, 14:47

Re: timezone у пользователя

Сообщение KiTE »

girmate писал(а): 2017.03.10, 11:42 Я всегда вешал события на до/после request. Запуск приложения это отдельное какое-то событие?
Да, именно это и имел ввиду. Или EVENT_BEFORE_REQUEST или EVENT_BEFORE_ACTION. В зависимости от того, на каком этапе вам важнее ориентироваться на зону пользователя. Для форматированного вывода во view без разницы, оба события подойдут.
girmate писал(а): 2017.03.10, 16:01 KiTE, еще попрошу Вас разъяснить мне один вопрос. С выводом даты/времени вроде разобрались. А как правильно сохранять?

Пользователь из Нью-Йорка поставил в расписание "сходить на ланч в 23:52" (дата в будущем).
Житель из Омска хочет увидеть, что Японец пойдет на ланч по своему местному времени. Допустим, в 13:52 (для примера).

Как правильно это организовать? Какой функцией я должен буду воспользоваться?
Я так понимаю, что Нужно взять дату/время ланча Японца, привести его к времени в UTC (а тут уже нужно учитывать временное смещение японца) и сохранить.
И тогда житель Омска увидит, что Японец собирается на ланч в 13:52.
В базе даты лучше всего хранить в виде временных меток, тогда для каждого пользователя они будут форматироваться индивидуально под его зону.

С датами из будущего могут быть нюансы. Связаны они с тем, что нельзя предсказать как в будущем могут меняться переходы с летнего на зимнее время для каждой зоны. И сохраненная ранее метка для будущей даты 2017-07-07 22:00 может превратиться в 23:00 с учетом не запланированного ранее изменения в переходах на летнее время. На этот счет была хорошая статья на хабре, но я так с ходу ссылку не найду.
girmate писал(а): 2017.03.10, 16:16 Значит в БД я должен буду положить $date->format('U'); ?
\DateTime::getTimestamp()
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: timezone у пользователя

Сообщение girmate »

Очень благодарен. Спасибо.

Наверное одна из этих статей:
https://habrahabr.ru/post/69983/
https://habrahabr.ru/post/61391/
Осторожно! Вы общаетесь с новичком ;)
Ответить