Хром, укравший рождество

    Я люблю свою профессию. Сидишь, никого не трогаешь, починяешь примус пишешь код. К тебе подходит тестировщик и говорит, что в календаре на сайте в 2015 году нет рождества. Ты спокойно отвечаешь, что такого не бывает, открываешь страничку у себя и показываешь что все хорошо. Вот только тестировщику от этого не легче. Потому что у него действительно нет рождества.

    Что ж, надо искать проблему


    Первым делом сравниваем браузеры. Ошибка повторяется только в хроме. И почему-то только у тестировщиков. Смотрим дальше. Повторяю действия один в один. Результаты выходят разные. Начинаем перебирать даты:

    new Date(2015, 0, 6);
    Tue Jan 06 2015 00:00:00 GMT+0300 (RTZ 2 (зима))
    new Date(2015, 0, 7);
    Tue Jan 06 2015 23:00:00 GMT+0300 (RTZ 2 (зима))
    new Date(2015, 0, 8);
    Thu Jan 08 2015 00:00:00 GMT+0400 (RTZ 2 (лето))
    

    Сравниваем с моим результатом:

    new Date(2015, 0, 7);
    Wed Jan 07 2015 00:00:00 GMT+0300 (Russian Standard Time)
    

    И забавное следствие:

    new Date(2015, 0, 6).getDate() === new Date(2015, 0, 7).getDate();
    true
    


    RTZ


    Загадка была разгадана и оказалась весьма банальной. 23 сентября Майкрософт выпустила обновление KB2998527(отдельный, более подробный пост об этом событии). Как оказалось, обновление дошло не до всех компьютеров, и повезло больше всех почему-то тестировщикам. Единственным браузером, некорректно работающим с новой таймзоной, оказался только хром. Стоит заметить что пропадает не рождество, а каждая первая среда нового года (видимо в связи с переходом на летнее время, да). Результат — календари, написанные на js, зачастую ошибаются и показывают неверные даты:
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 69
    • 0
      Вангую, что команда разработчиков Хрома добавит еще один regression-тест :)
      • +25
        Пост закончился внезапно. После «зачастую ошибаются и показывают неверные даты» ожидал увидеть ещё текст, но его не было
        • +5
          Все закончилось хорошо. Ошибка (на сайте) поправлена, рождество (не везде, конечно) спасено, тестировщики довольны.
          • +1
            Вспомнился мультик, где «рождество отменено и всё это из-за мальчика по имени Джимми Нейтрон» (на 12:13) ( vk.com/video?q=%D0%B4%D0%B6%D0%B8%D0%BC%D0%BC%D0%B8%20%D0%BD%D0%B5%D0%B9%D1%82%D1%80%D0%BE%D0%BD%20%D1%80%D0%BE%D0%B6%D0%B4%D0%B5%D1%81%D1%82%D0%B2%D0%BE§ion=search )
          • 0
            Как поправили-то?
            • +1
              В своем коде, где нужны были только даты — добавил три лишних часа. Даты остались датами, но теперь правильными.
              Сторонний код править зачастую себе дороже, поэтому для jQueryUI календаря не правил ничего, там и проблема ближайшая в 2020 году.
              • 0
                Спасибо!
                Какой веселый костыль) Ну, а комментарий оставили, почему так сделали? Чтоб потом никто не матерился: «Какой му*ак тут прибавляет к датам 3 часа?».
                Всё же надеюсь, что MS выпустит какой-то другой патч, исправляющий эту ошибку.
                • +1
                  Да, оставил todo: «проверить в новых версиях и удалить за ненадобностью».
                  • +1
                    написал сегодня похожее сообщение, пока не стал удалять, так как в нем указал возможное решение.
                    Календарь в jquery ui я исправил следующим образом:
                    — если старая версия, то необходимо поменять функцию
                    	/* Find the number of days in a given month. */
                    	_getDaysInMonth: function(year, month) {
                    		return new Date(year, month+1, 0).getDate();
                    	},
                    

                    Без данного исправления декабрь 2013 состоял из 1 дня (тут украли не то что рождество, а целый месяц). В актуальных версиях эта функция работает правильно.
                    Кроме того, необходимо изменить функцию вычисления дня недели первого дня месяца, добавив к дате хотя бы 1 час (4-й аргумент):
                    	/* Find the day of the week of the first of a month. */
                    	_getFirstDayOfMonth: function(year, month) {
                    		return new Date(year, month, 1, 1).getDay();
                    	},
                    

                    И это не проблема 2020 года. Без данного исправления неправильно отображается уже январь 2014 — как будто он начался во вторник.

                    Проблема с датами в хроме (в ближайшем обновлении будет исправлена) и в эксплорере. После указанного исправления календарь везде работает нормально.
        • +10
          Если погулять по ссылкам, то можно много интересного накопать: в Сан-Паулу пропало 18е октября (как следствие в Chrome canary всё уже пофикшено), Сиднее пропало 6е октября (правда это уже в Safari), заметки с iPhone пропадают…

          Каким местом это всё писалось, интересно, что такой фееричный результат достигнут?
          • +6
            Просто даты такая сумрачная материя, что только кристально чистые адепты могут не натворить в ней делов.
            А поскольку таких нет, и все мы люди и иногда ошибаемся, то и получается такой результат.
            На эту тему есть отличный сборник заблуждений: habrahabr.ru/post/146109/
            • +2
              Ещё многие думают, что каждый четвёртый год — високосный. Ожидал увидеть это в списке заблуждений.
            • +3
              Ещё в копилку: OpenOffice.org won’t print on Tuesdays.
            • +1
              Только ли в хроме дело?
              Буквально вчера в FireFox наблюдал занятный эффект в календаре на главной странице одного сайта — смещение дат на 1 день назад. Эффект действует до 7-го января включительно.
              image
              • 0
                Вроде Firefox тоже затронут, хотя неясно как именно.
                • –1
                  Хотя строго говоря, это не проблема браузера(-ов).
                  Браузеры опираются на API OS и просто транслируют все чудеса, которые были принесены кривым обновлением.
                  • 0
                    Тогда почему сломалось не везде?
                    • 0
                      Думаю, что некоторые реализации опираются на иные источники данных о часовых поясах (например на tz database). Но даже в этом случае не факт, что всё хорошо — как минимум текущая дата/время предоставляется операционкой. Принцип GIGO никто не отменял.
                      • 0
                        А как вы объясните то, что в Хроме в зоне -3 (Бразилия) тоже есть баг:
                        new Date("October 19, 2014");//Sat Oct 18 2014 23:00:00 GMT-0300
                        


                        даже без обновления KB2998527 Винды!
                        • +3
                          Разные причины ошибок.

                          То о чём вы говорите, похоже, решено в этом фиксе: diff/1/src/date.h. И конкретно это — ошибка разработчиков браузера (в DaylightSavingsOffsetInMs нужно передавать локальное время, а они передали UTC).

                          Однако обратите внимание на функцию GetLocalOffsetFromOS — она берёт смещение локального времени у ОС.

                          virtual int GetLocalOffsetFromOS() {
                          double offset = base::OS::LocalTimeOffset(tz_cache_);
                          DCHECK(offset < kInvalidLocalOffsetInMs);
                          return static_cast(offset);
                          }

                          Т.е. хром использует базу часовых поясов операционки и это является причиной обсуждаемой проблемы с KB2998527.

                          <лирика>
                          Если у вас есть подвесной мост, то он может упасть по различным причинам — отвалится либо один конец, либо второй (или оба) — тут аналогичный случай.
                          </лирика>
                          • 0
                            То о чём вы говорите, похоже, решено в этом фиксе: diff/1/src/date.h.

                            Можете объяснить смысл исправления? Я уже с десяток раз пытаюсь понять разницу между
                            time_ms += LocalOffsetInMs();
                            return time_ms + DaylightSavingsOffsetInMs(time_ms);
                            и
                            return time_ms + LocalOffsetInMs() + DaylightSavingsOffsetInMs(time_ms);
                            • +2
                              В первом случае (если записать так же, как во втором):
                              return time_ms + LocalOffsetInMs() + DaylightSavingOffsetInMs( time_ms + LocalOffstInMs() );
                  • 0
                    Вот так: https://bugzilla.mozilla.org/show_bug.cgi?id=1074821

                    Но я уже понял (я писал этот тикет) что FF ведет себя правильно полностью соответствуя тому, что ему говорит ОС. А вот в Chrome есть другой баг https://code.google.com/p/v8/issues/detail?id=3116 который и привел к вылетанию часа 2014.01.01.

                    Не факт, но возможно что каждая первая среда года вылетает по той же причине
                    • 0
                      там написано, что Файрфокс добавляет час.
                  • +47
                    «И тут откуда-то выползает мой тестировщик, без Рождества. Ему больно! Но он подползает и говорит мне:
                    — Разработчииииик! Я Рождества не чувствую…
                    А я ему:
                    — А у тебя его нет!»
                    image
                    • +2
                      У меня из-за этой же причины разворотило графики amCharts:

                      image

                      Как лечить не придумал, кроме как заменить часовой пояс в системе.
                      • +1
                        Долго не мог понять, что автор тестирует и на что жалуется, пока не понял, что речь про православное рождество. Первым в голову почему-то пришло католическое
                        • +3
                          Наверное, потому, что недели в календаре оканчиваются субботою, а это принято в Новом свете и в Юго-Восточной Азии, где юлианский календарь («православное рождество»), наоборот, не в обычае. Вот карта, на которой синим отмечены те страны, где неделя оканчивается субботою, жёлтым — где воскресеньем, а зелёным — где пятницею:

                          [карта]

                          При этом и воскресное начало недели, и юлианский календарь по сути относятся к культурному наследию тысячелетней жизни православного государства Восточной Римской Империи (которая, в свою очередь, почерпнула их из более древних источников). Просто наследство это неравномерно распределено.

                          По карте также ясно, что день окончания недели может иметь и вероисповедное значение: видно, например, что пятничное окончание недели принято в исламских странах, а субботнее — в Государстве Израиль (и в США, где евреев не меньше).
                          • +3
                            А в странах, отмеченных серым цветом в какой день неделя начинается?
                            • +8
                              «Как назло на острове нет календаря,
                              Ребятня и взрослые пропадают зря.
                              Ребятня и взрослые пропадают зря,
                              На проклятом острове нет календаря.»
                              • 0
                                Пабапапам оуе
                              • 0
                                А по этим странам у авторов карты, по-видимому, просто не было свéдений.
                              • 0
                                А в Китае тоже много евреев?
                            • 0
                              Поставил апдейт от майкрософта, теперь тоже нет Рождества(
                              new Date(2015, 0, 7);
                              Tue Jan 06 2015 23:00:00 GMT+0500 (Russia TZ 4 Standard Time)
                              

                              • 0
                                Это вывод по умолчанию в UTC формате, сделай преобразование .toString() хотя бы.
                                • 0
                                  автор топика .toString() не вызывал, поэтому я поступил аналогично
                                  • 0
                                    Тогда соблюдайте аналогию полностью и для проверки вызывайте .getDate() ведь это важнее, чем просто созданный объект. У вас не ошибка, создайте любую Date и получите на день меньше.
                                    • +1
                                      У меня нет апдейта винды

                                      new Date(2015, 0, 7);
                                      Wed Jan 07 2015 00:00:00 GMT+0400 (Russian Standard Time)
                                      


                                      У меня тоже не ошибка?

                                      >>и для проверки вызывайте .getDate()
                                      >>создайте любую Date и получите на день меньше.

                                      var d = new Date(2015, 0, 7);
                                      d.getDate();//7
                                      
                                      var d = new Date(2015, 10, 7);
                                      d.getDate();//7
                                      


                                      что-то я не получаю на день меньше
                                      • 0
                                        И у вас и у Рината всё норм. Вообще представление объекта Date может быть каким угодно в отладчике, поэтому преставления в виде вывода консоли не корректны (т.е. первая вставка кода, а вот со второй всё норм)) Потому что:
                                        Даже если там напишет «На день раньше четверга в месяц, что идёт перед високосным, год являющийся разницей двойки в 11-ой степени и 33, время выхода Бетмена на охоту, т.е. полночь ровно» это будет корректно) Интересно именно что getDate() вернёт, равно как и toString().

                                        Хех, даже в своих багах винь не постоянна)
                                        • 0
                                          вывод в консоль — это неявный вызов toString() и есть.
                                          getDate возвращает число в месяце, а не саму дату.

                                          new Date(2015, 0, 7);
                                          Tue Jan 06 2015 23:00:00 GMT+0500 (Russia TZ 4 Standard Time)
                                          


                                          всё же это ошибка, хотя бы потому, что Date(2015, 0, 7); — это локальное время, и 7 января никогда переводов часов не было
                                          • 0
                                            Вы не правы, вывод в консоль объекта это не обязательно вызов toString. Скажу больше, в последних версиях webkit-gekko браузерах это не так почти всегда: сравните вывод
                                            1 и (1).toString()
                                            {} и ({}).toString()
                                            можете проделать с датой то же самое в Firefox.

                                            Представление объектов в отладочной консоли дело сугубо разработчика и доков контролирующих это я не встречал (хотя и просмотрел w3c доков прилично).

                                            А вот предположить, что ошибка в указании временной зоны +5 это можно. Проверить можно вызвав getTimezoneOffset(). И если он не -240 (разница между UTC и локальным временем в минутах) это будет настоящая ошибка.

                                            Ошибка же в представлении данных есть, но даже если числа будут в стиле хищника вряд ли можно считать её критичной. В отличии от хранимой даты.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  Правильное решение — не использовать метку времени для описания дат. Дата должна описываться тремя числами: годом, месяцем и днём.
                                  Когда вы пишете: new Date(2015, 0, 7);
                                  Вы на самом деле получаете: new Date(2015, 0, 7, 0, 0, 0);
                                  Со всеми вытекающими отсюда проблемами с часовыми поясами и тп.
                                  Что использовать вместо Date? Например, неплохую библиотеку.
                                  • 0
                                    Вообще-то, просто нужно явно указывать часовой пояс и хранить все даты в UTC.
                                    • +2
                                      Нужно указывать ровно то, что нужно, и не нужно указывать то, что не нужно. Для указания даты «седьмое сентября 2014 года» не нужно знание о часовом поясе, летних сдвигах, високосных секундах, фазе луны или гендерной самоидентификации пользователя.
                                  • +3
                                    и повезло больше всех почему-то тестировщикам

                                    тестировщики должны страдать.
                                    • +1
                                      Я бы сказал, как Windows украл рождество) Всё-таки хромы под маками и линухами в грехах не замечены)
                                      • 0
                                        Но почему тогда в IE11 все нормально?
                                        • +1
                                          Давайте заглянем в исходники IE11. Ах да, забыл, что они не опубликованы…
                                          А если почти серьёзно, то в Chromium by Linux всё нормально, выше разбиралось, что смещение временной зоны получается через API. И по сути любой календарь работающий с данным API выдаст странность при таком же алгоритме.
                                          И совсем доказательство: наличие исправления доказывает наличие ошибки. А значит вина за ошибку на МягкомСофте. ч.т.д.
                                          • 0
                                            Разработчики хромиума же подтвердили наличие проблемы, и исправление уже внесено в код браузера (V8) — должно появиться в 38-ой версии
                                            • 0
                                              я прочитал code.google.com/p/chromium/issues/detail?id=417640 и не совсем понял, баг пофиксят в 38 и 39 версии?
                                              • 0
                                                Я особо не слежу за развитием событий, но видел просьбу автора патча бекпортировать и включить в 38. Не знаю, договорились или нет
                                            • 0
                                              Перечитайте коментарии выше — вина в неправильном вызове API
                                              • 0
                                                Как писали выше, ещё раз трабл: тут
                                                Так же описанные изменения в этом комментарии.

                                                Да, в хроме есть ошибка, но спровоцировало её выявление ошибка в Win7 update.
                                                • 0
                                                  по каким критериям вы решили, что это ошибка Винды?
                                                  • 0
                                                    По тому, что на это выпустили патч, разумеется.
                                                    Ну и не смотря на наличие бага в линухах хромиумы берут дату адекватно. Проверено.
                                                    • 0
                                                      Никто на это не выпускал патч в МС, это патч с изменениями в часовых поясах, а не исправление правильно работающего API.

                                                      Вызывали неправильно — да. Но это проблема хромиума.
                                                      • 0
                                                        Кто выпустил патч? Гугл?
                                                        Причем тут обновление винды тогда?
                                                        Почему Мозилла не выпускала никаких патчей, если это обновление вызывает ошибки?

                                                        Странно, что в линухе Хром работает.
                                                        Какой часовой пояс? Есть ли перевод часов?
                                                        • 0
                                                          Патчи обе конторы выпустили.
                                                          Винда патч с зимним временем, а хром с этими прибавлениями/вычитаниями.
                                                          У Мозиллы своя атмосфера, там иначе проявляется и опять таки в только в Окошках.

                                                          Ничего странного: API получения времени и смещения разное) Мог бы поискать пруф этой части, но я уже так намыкался с исходниками Хромиума, что почти уверен, что и эта часть под разные платформы с разной реализацией)
                                                          +4, есть.
                                                          • 0
                                                            Микрософт выпустил патч, чтобы сделать постоянный перевод часов на +3, а не для исправления какой-либо ошибки.

                                                            Я думаю так: была ошибка в Хроме, она не проявлялась, до тех пор пока Микрософт не выпустила обновление на постоянное +3.
                                                            Микрософт выпустила обновление, ошибка в Хроме проявилась.
                                                            В Линухе никто обновление на постоянное +3 не выпускал, поэтому ошибка в Хроме осталась не замеченной.
                                                • 0
                                                  Давайте заглянем в исходники IE11. Ах да, забыл, что они не опубликованы…

                                                  А зачем туда заглядывать? Проблема же в хроме. Ну в общем все понятно с вами :)
                                                  • 0
                                                    Чтобы ответить на вопрос почему в 11 осле всё хорошо. Очевидно, Ватсон!
                                                    • 0
                                                      Любому кодеру может и очевидно, но проблему надо искать у себя :)
                                                      • 0
                                                        «У тебя чё, проблемы?»
                                                        М.б. и надо, только ответить почему в осле всё нормально это не поможет)) Иного способа ответить правильно на этот вопрос я не вижу) Хотя наверняка он есть, но я не силён в реверс-инженеринге и прочих метадах аналитической диагностики)
                                            • 0
                                              image
                                              • 0
                                                В первую среду каждого года этот нелепый переход с зимнего на летнее время. Но это ладно, в основном попадает на праздники.
                                                Но ведь логика подсказывает, что где-то в середине года должен быть и обратный переход! Может, RTZ — это часть санкций? :)
                                                • 0
                                                  А ослик молодец!)
                                                • 0
                                                  Вот нашел решение для подобных проблем, автор утверждает что должно помочь. Это патч на JavaScript который нужно применить до загрузки каких либо скриптов работающих с датой и временем. При этом отпадет необходимость делать правки в старых скриптах.

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.