Часовые пояса
Земной шар делится на 24 часовых пояса. Точкой отсчета считается всемирное координированное время (UTC). Стандарт, который играет роль нуля в списке часовых поясов. Часовые пояса вокруг земного шара выражаются, как положительное или отрицательное смещение от UTC.
К примеру Москва это UTC/GMT +3 часа, а Новосибирск UTC/GMT +7 часов.
Стоит также учитывать, что в некоторых странах осуществляют переход на летнее и зимнее время, что еще более усугубляет понимание всего этого.
Как работать со временем
Важно все расчеты со временем вести относительно UTC
При разработке проектов нужно прийти к соглашению, что все даты хранятся как локальной время по UTC. Так легче производить конвертацию.
Все современные библиотеки имеют функции для работы с таким временем.
Например, в javascript
для этих целей можно воспользоваться библиотекой https://momentjs.com/.
В php
легко и приятно работать со временем позволяет библиотека https://carbon.nesbot.com/.
Клиент и сервер должны обмениваться друг с другом только датами в UTC. Перевод уже делать на стороне клиента исходя из локального смещения пользователя.
Хранение дат в timestamp требует постоянной конвертации, что не оптимально. Базы данных лучше сами оптимизируют дату храня ее в специальном формате.
Локальное смещение пользователя
Для того чтобы узнать локальное смещение пользователя на клиенте можно воспользоваться методом getTimezoneOffset()
в js.
(new Date()).getTimezoneOffset()
-180
Это значит смещение часового пояса, являющееся разностью в минутах между временем UTC и местным временем.
В данном случае -180 минут
означает +3 часа
, а +240
будет значить -4 часа
.
Но если у клиента введено летнее или зимнее время, смещение будет не постоянным, даже в пределах одного часового пояса.
Обратная процедура преобразования на сервере означает вычитание(прибавление) минут с обратным знаком, об этом нужно помнить.
Например, в php преобразовать всемирное время в локальную дату можно таким образом:
<?php
$date = new DateTimeImmutable('now', new DateTimeZone('Europe/Moscow'));
$date->format('d-m-Y H:i:s e I O T'); // 02-05-2021 17:08:56 Europe/Moscow 0 +0300 MSK
$date->format('c'); // 2021-05-02T17:08:56+03:00
$date->format('r'); // Sun, 02 May 2021 17:08:56 +0300
$date->format('U'); // 1619964536
Итог
- хранить даты на сервере только в UTC, если с определенной зоной, то явно указывая это.
- для перевода дат на клиенте использовать специальные библиотеки для этого, не пишите собственные велосипеды.
- клиент и сервер должны обмениваться друг с другом только датами в UTC.
- если вы что-то вычитаете или прибавляете к дате, значит вы делаете что-то не так.