[Из песочницы] Javascript и часовые пояса — правильное время на сайте

До сих пор существует путаница при реализации местного времени на сайте. Изрядный вклад в эту путаницу внесли российские законодатели с периодической отменой перехода на зимнее время. Вот Вы знаете какой сейчас у нас часовой пояс +3 или +4 часа? Вот и большинство пользователей этого не знают. Но есть очень простое решение как не отягощать пользователя этой проблемой! Нужно использовать время устройства (исходим из того, что это корректное местное время). Очевидное решение использовать функцию javascript getTimezoneOffset является в корне неправильным. Почему? Читайте дальше.
Как всё должно работать? Если пользователь отправляет своё сообщение например на форуме в 12:15 (по времени на его устройстве), то и увидеть своё сообщение на сайте он должен с этим же временем. Казалось бы, что если использовать смещение часового пояса (взятое из браузера из getTimezoneOffset), то всё должно работать. Но это не так!

Парадокс в том, что часовой пояс может быть неправильно установлен на устройстве пользователя. И это весьма распространённый случай, так как при смене часового пояса многие просто переводят время на несколько часов не трогая часового пояса. И как следствие мы имеем бесконечные ветки на форумах техподдержки «Настройка времени», которые расцветают при каждом переводе часов зима/лето или в период возвращения из отпусков.

Самое правильное — выставлять местное время на сайте в соответствии с временем установленным на устройстве пользователя не обращая внимание на часовой пояс. Исходим из того, что на сервере все даты хранятся в базе данных в формате GMT (и это правильно). Таким образом для правильного вывода дат (времени) в браузере пользователя нужно вычислить смещение между временем браузера и сервера.

На сервере текущее время в php можно получить функцией time (), в браузере функцией javascript Date (). И тогда смещение часового пояса можно вычислить при помощи javacript так:

// вычисление time_zone в минутах в браузере
var d = new Date();
var loc = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
var time_zone = (( - loc/1000)/60).toFixed(0);


Далее нужно передать значение time_zone на сервер и выводить время из БД с учётом этого смещения. Например если время хранится в БД в секундах, то для вывода в браузер используем следующее (на php):

// время для вывода в браузер - вычисляется на сервере
$t = $time_fromDB - $time_zone*60;


Выше изложен двух-этапный метод:
1. Вначале вычисляется time_zone
2. time_zone отправляется на сервер и используется при дальнейшем выводе времени

Но можно всё сделать и в один этап. В этом случае при первой загрузке страницы в браузер так же вычисляется time_zone (см. выше) и далее все значения времени выводятся при помощи javacript. Например при помощи такой функции mydate ():

function two(num) { return ("0" + num).slice(-2);} // подставляет недостающий ноль 

// t - время в секундах из БД сервера
// mydate возвращает строку  в формате например 12.08.2015 19:03
function mydate(t) {
  var d = new Date((t-time_zone*60)*1000);
  return two(d.getUTCDate())+'.'+ two(d.getUTCMonth()+1)+'.'+d.getUTCFullYear()+' '+ two(d.getUTCHours())+':'+ two(d.getUTCMinutes());
}


Всё вышеизложенное успешно используется в нашем проекте месcенджера, где прекрасно себя зарекомендовало во всех браузерах и операционных системах (мобильных и настольных). Возможно неограниченное использование приведённого здесь алгоритма в ваших проектах. Приветствуется ссылка в исходных кодах на наш проект magdialog.ru.

© Habrahabr.ru