К содержимому

Три часовых пояса в одном звонке

Звонок в отчёте на несколько часов раньше или позже, чем был на самом деле.

phpmysql

Отчёт по звонкам показывает разговор в четыре утра. Разговор был днём. На другом стенде тот же звонок отображается верно.

Причина

В одном звонке участвуют минимум три пояса:

  • провайдер отдаёт метки в UTC — так делают почти все;
  • сервер приложения живёт в своём поясе, и функции вроде now() возвращают локальное время;
  • человек, который смотрит отчёт, находится в третьем.

Ошибка возникает там, где метку сохранили как есть, не обозначив пояс. Дальше её читают уже с другим предположением, и разница въезжает в данные молча: исключения нет, просто число другое.

Отдельно подставляет база: соединение может иметь собственный часовой пояс, отличный от системного. Одна и та же вставка через разные подключения ляжет по-разному.

Решение

Правило простое и работает всегда:

Храним в UTC. Конвертируем только на выводе. Метку без пояса не принимаем.

По шагам:

Приём. Разбирать метку провайдера с явным поясом, а не полагаться на дефолт среды. Если провайдер прислал Z или смещение — использовать его.

Хранение. В UTC, в поле, которое не пересчитывается автоматически. Часовой пояс соединения с базой задавать явно при подключении, а не наследовать от сервера.

Вывод. Переводить в пояс того, кто смотрит. Для отчётов, которые уходят заказчику, пояс лучше писать прямо рядом с временем — тогда расхождение видно сразу, а не через месяц в претензии.

Где это ломается чаще всего

Границы суток. Отчёт «за вчера» при разнице в несколько часов захватывает кусок позавчера или теряет вечер. Проверять фичу нужно именно на границе, а не в середине дня — в середине всё сходится при любой ошибке.

Переход на летнее время. Там, где он есть, смещение меняется дважды в год. Хранение в UTC это переживает, хранение в локальном — нет: час либо повторяется, либо исчезает.

Как убедиться, что починено

Взять звонок и сравнить три значения: что показал провайдер в своей панели, что лежит в базе, что видно в отчёте. Первое и третье должны совпадать после приведения к одному поясу, а в базе должен быть UTC.

Если совпадает — можно спать спокойно. До перехода на летнее время.

Дальше

Новые разборы выходят в Telegram раньше, чем попадают сюда. Без анонсов курсов — только материалы.

Читать в Telegram →