voskobovich
@voskobovich
PHP Developer | 8+ years exp.

PHP, Yii2 и PostgreSQL. Как сделать поддержку временных зон для юзеров?

У меня типовая задача - сделать приложение с поддержкой временных зон (чтобы юзер в настройках выбирал свою таймзону).
Использоваться это будет для дат создания\обновления записей в базу, время логина юзера, время фиксации лога.

Изучая тему я узнал, что для моей задачи правильным будет вариант хранения даты в UTC, а на клиенте при записи и отображении переводить в временную зону пользователя.

Но вот здесь есть несколько нюансов:
1. Как быть с переходами на зимнее\летнее время?
Ведь дата сохраненная год назад в UTC сегодня может отображаться не правильно.
Я не нашел исчерпывающей информации по этому вопросу и не до конца в нем разобрался.
Читал про базу tzdata которая помогает корректно конвертировать прошедшие даты, но опять же не понял как пользоватся. Неужели нужно самому писать логику работы с ней?
2. Пишут, что PostgreSQL хорошо умеет работать с таймзонами.
То есть создаем тип timestamp with timezone и база все делает за меня.
Но здесь снова не понятки.
2.1 Как база узнает таймзону клиента? Видимо нужно слать запрос вроде SET SESSION TimeZone TO -5; при каждом коннекте к базе, костыль какой-то.
2.2 Формат даты который увидит пользователь - это уровень отображения, а я пытаюсь решить его на уровне данных, а то и бизнес логики. Мне кажется это не верно.
3. Если реализацию перевод Таймзона => UTC и обратно делать при отображении, то как это реализуется в коде?
В какой таймзоне инициализировать приложение (date_default_timezone_set) ?
Как переводить время и в какой момент времени?

Пишите ответы на вопросы и свои рецепты решения.
Мне будет полезна любая информация.
Спасибо!
  • Вопрос задан
  • 2080 просмотров
Решения вопроса 1
voskobovich
@voskobovich Автор вопроса
PHP Developer | 8+ years exp.
Вот тезисно ответы на мой вопрос
1. В бд хранить даты нужно в UTC
2. Yii2 Formatter умеет из коробки **при выводе** учитывать таймзону. Настраиваешь таймзону, передает в него время в UTC и он сам все сдалет за тебя.
3. Yii2 Date Validator умеет из коробки **при записи** даты в атрибут модели конвертировать ее обратно в UTC и отдавать в указанный в настроках валидатора атрибут модели, чтобы дальше оперировать даными опять же в UTC.
4. После логина юзера нужно именить у форматтера timeZone на указанную в профиле залогиненого юзера. Пока юзер не залогинен - работаем в UTC.
5. В UTC нужно перевести ОС, БД и PHP. Соответственно
date_default_timezone_set('UTC'); или в php.ini
6. Формат времени лучше не перекладывать на базу, так как переезд на другую базу или взятие данных из кэша все сломают.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Не знаю как в чистом PHP это сделать, но в Yii 2 достаточно сделать так.
config/main.php
'components' => [
    'formatter' => [
       'dateFormat' => 'd.MM.Y',
       'timeFormat' => 'H:mm:ss',
       'datetimeFormat' => 'd.MM.Y H:mm',
   ],
],


Вывод времени и даты
/* Тут идет установка часового пояса
* естественно вы можете хранить их в кэше или БД 
* или вычислять по IP или JS. Тайм зоны можно хранить 
* в разных форматах. Лучше в UTC, а еще лучше в
* UNIX timestamp. 1412599260 / 2014-10-06 12:41:00
*/

$myTimeZone = "Europe/Berlin"; 

Yii::$app->timeZone = $myTimeZone;
Yii::$app->getFormatter()->asDate(time()); // время 
Yii::$app->getFormatter()->asDatetime(time()); // Дата и время


Если не изменяет память, то можно так с тайм зоной работать. Естественно можно сделать виджет и постить где вам нужно.

Список тайм доступных тайм зон в PHP

UPD: По поводу летнего времени. Можно в форме профиля прикрутить чекбокс "учитывать летнее время", а потом сделать в БД триггер, который в определенную дату менял бы таймштампы +1 и -1 час.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы