[Из песочницы] Решение проблем с RTZ2 после Microsoft Update KB2998527
После выпуска упомянутого выше обновления многие разработчики столкнулись с проблемами. На текущий момент в Chrome проблему хоть как-то попытались исправить, а в IE10 (Document mode=«Standarts») все работает хорошо, но в более старых браузерах и режимах совместимости IE вся работа с датами развалилась.Так сложилось, что из-за технических ограничений я вынужден поддерживать работу разрабатываемых мной приложений в IE8–9–10 и Chrome. Кроме того, для работы с датами использую библиотеку momentjs.
Поскольку дата релиза была за горами, то, поискав на просторах всемирной паутины решение проблемы и не найдя его, я решил, что рано или поздно разработчики браузеров решат эту проблему и мне не придется ничего менять. Но релиз всё ближе, а решения как не было, так и нет.
И вот настало время решить эту проблему самостоятельно.Кратко опишу основные проблемы в виде таблицы (неожиданные результаты зачеркнуты):
IE10(IE8 standarts) IE9(all document modes) IE10(IE10 standarts) Chrome 38.0.2125.122 m new Date (2014, 0, 1) Tue Dec 31 23:00:00 UTC+0300 2013 Wed Jan 1 00:00:00 UTC+0300 2014 Wed Jan 1 00:00:00 UTC+0400 2014 Wed Jan 01 2014 01:00:00 GMT+0400 new Date (2015, 0, 7) Tue Jan 6 23:00:00 UTC+0300 2015 Tue Jan 6 23:00:00 UTC+0300 2015 Wed Jan 7 00:00:00 UTC+0300 2015 Wed Jan 07 2015 01:00:00 GMT+0400 moment ().startOf ('year') Tue Dec 31 23:00:00 UTC+0300 2013 Wed Jan 1 00:00:00 UTC+0300 2014 Wed Jan 1 00:00:00 UTC+0400 2014 Wed Jan 01 2014 01:00:00 GMT+0400 moment ().endOf ('year') Wed Dec 31 22:59:59 UTC+0300 2014 Wed Dec 31 23:59:59 UTC+0300 2014 Wed Dec 31 23:59:59 UTC+0300 2014 Thu Jan 01 2015 00:59:59 GMT+0300 Первое, что пришло на ум — это доработать библиотеку работы с датами (momentjs) для корректного вычисления моментов времени и повсеместно её использовать вместо оригинального объекта Date или найти альтернативную библиотеку. Посмотрел datejs, xdate, tzdata-javascript. Но переписывать уйму кода для «временного» решения проблем показалось слишком трудоёмким. Всё таки надежда на то, что проблемы с временной зоной исчезнут со следующими патчами браузеров остается.И тут пришла светлая мысль — поменять объект Date. Пусть он обрабатывает проблемные даты и приводит их к единому виду не зависящему от браузера. Т.е. new Date (2014, 0, 1) должен всегда создавать дату 01.01.2014 00:00 UTC+0400, тогда и momentjs.endOf ('year') будет правильно считать конец года.
Как же этого добиться?
Принцип такой — время в UTC+0000 непрерывно и ошибки реализации временной зоны на него не влияют, поэтому все манипуляции с датой можно производить именно в UTC. И вообще игнорировать работу с временной зоной в браузере раз она работает неправильно. Но эта доработка должна быть прозрачной для пользователя (Web-разработчика), т.е. он по прежнему должен видеть дату в своей локальной временной зоне.
Изучив спецификацию объекта Date, разработал следующий способ:
1. Необходимо переопределить конструктор Date так, чтобы он создавал время в UTC.Назовем оригинальный объект Date — NativeDate, а новый (исправленный) объект NewDate.Тогда NewDate (year, month, date) на самом деле будет выполнять код NativeDate (NativeDate.UTC (year, month, date)).2. Методы setTime, getTime и valueOf переопределять не нужно — они уже работают с UTC.3. Сеттеры и геттеры для свойств Date, Day, FullYear, Hours, Milliseconds, Minutes, Month, Seconds объекта NewDate делаем ссылками на сеттеры и геттеры аналогичных свойств с префиксом UTC объекта NativeDate. А сеттеры и геттеры с префиксом UTC для NewDate будут учитывать временную зону.После выполнения этих действий всё заработало просто отлично.
Однако для полной поддержки функциональности оригинального объекта Date потребовалось поддержать все варианты вызова конструктора Date, а также методы Date.parse, Date.UTC, Date.now и все возможные способы сериализации объекта в строку.
Получилось как-то так: rtz2fix.
Буду очень рад, если кто-то обнаружит проблемы в данном решении и сообщит о них мне.
Ссылки по теме«Хром, укравший рождество»; «Новая таймзона — новые проблемы».