http://habrahabr.ru/post/242459/
Редкому программисту случается избежать работы с датой и временем. Вообще, дата/время — базовое понятие и в основной массе языков существуют встроенные механизмы работы с этим типом данных. Казалось бы, JS не исключение, есть встроенный тип Date, есть куча функций в прототипе, однако…
Кто виноват
Первая проблема возникает когда нужно задать дату/время в тайм-зоне отличной от UTC и от локальной. Конструктор Date не имеет такого параметра.
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minute[, second[, millisecond]]]]]);
Единственный вариант, где можно указать смещение относительно UTC — третий способ. Вызов конструктора в этом формате позволяет передать смещение как часть строки:
new Date('Sun Feb 01 1998 00:00:00 GMT+0700')
Строка принимается в формате RFC2822, весьма неудобном и трудном к ручному вводу. Получить такую строку из пользовательского ввода практически невозможно. Я не могу себе представить человека, который бы согласился вводить дату в таком формате.
Не смотря на то, что в Date можно установить все параметры по отдельности для таймзоны UTC — проблемы это не решает – таймзона останется локальной. Но это не единственная проблема.
Смещение относительно UTC — не константа. Это функция от даты, времени (ну или от таймштампа, если угодно) и, опять же, тайм-зоны. Например, для Москвы последний перевод времени даёт:
new Date(2014, 9, 25, 0, 0, 0); // 26.10.2014, 21:00:00 GMT+3
new Date(2014, 9, 27, 0, 0, 0); // 25.10.2014, 22:00:00 GMT+4
Таким образом, конструктор в третьем варианте становится практически бесполезным поскольку смещение нужно знать заранее. А оно, как было сказано, так просто получено быть не может. Единственная библиотека, из попавшихся мне, которая использует базу данных
Олсона для обсчета сдвигов —
timezone-JS. Проблема использования этой библиотеки в том, что низлежащие библиотеки (date/time picker-ы) про неё ничего не знают и внутри активно используют стандартный Date. Остальные библиотеки, работающие с объектом Date, явно на эту базу не ссылаются и обновления из нее не получают. (Поправьте меня в комментариях)
В бизнес применении тайм-зоны имеют смысл только если заданы дата и время. К примеру, если рабочий день начинается в 9:00, то вряд ли вы ожидаете что ваш коллега из Владивостока начнет работать в 15:00. Таймзоны учитываться не должны и в таком случае отображать дату нужно в UTC. Однако, в случае с регулярными событиями, происходящими в один момент времени в разных часовых поясах, таймзона все таки нужна. К примеру, ваш ежедневный скрам начинается в 10:00 для вас и в 13:00 для Новосибирска. Между прочим, в этом как раз и есть разница между GMT и UTC. UTC – это время без смещения, а GMT – это время со смещением 0. Поясню на примере:
31.12.2014, 20:59:59 GMT в Московском часовом поясе должно выглядеть как 31.12.2014, 23:59:59
31.12.2014, 20:59:59 UTC в Московском часовом поясе должно выглядеть как 31.12.2014, 20:59:59
Из-за этой арифметики их в основном и путают. К сожалению, напутано с этим параметром повсеместно. Отсутствие прямого указания таймзоны в JS трактуется как локальная таймзона, а указание UTC и GMT равнозначно.
В ситуации мог бы помочь
Intl. Мог бы, но не обязан. В частности, там есть такой параметр timeZone, но, чуть далее стандартом определено: The time zone to use. The only value implementations must recognize is «UTC». В настоящее время кроме Chrome не один браузер произвольные таймзоны не поддерживает.
С диапазонами времени в JS все совсем плохо — ничего подобного в языке нет. Хочешь сделать хорошо – делай сам.
Что делать.
Вариант 1.
Не использовать произвольную таймзону. Вариант предпочтительный и, наверное, самый безболезненный. То есть, у вас есть только локальная таймзона и UTC. Для этих случаев во всех браузерах вроде как всё есть, пусть и не очень удобно. К тому же, таймзона выставляется глобально для ОС и менять ее для конкретного web-приложения некошерно.
Вариант 2.
Если произвольные таймзоны необходимы — не использовать таймштамп. Совсем. Храните время в сберегательной кассе в RFC строке с указанием таймзоны. Не уверен что это поможет победить сдвиги таймзоны в кроссбраузерном понимании, но, как минимум, Chrome о таких сдвигах в курсе.
Вариант 3.
Ситуации бывают разные и случается так, что в базу время записывается с какого ни будь устройства. То есть в виде таймштампа. Тут бежать некуда, что бы корректно отобразить время нужно знать либо таймзону устройства, либо таймзону пользователя, либо и того и другого и обсчитывать все сдвиги врукопашную. Без использования базы Олсона тут не обойтись.
Тут должна быть мораль сей басни, но добавить мне пока больше нечего. В черновиках стандарта ECMA я никаких подвижек не наблюдаю, наверное, их и не будет.