Пользователь
0,0
рейтинг
6 октября 2014 в 22:21

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

Я люблю свою профессию. Сидишь, никого не трогаешь, починяешь примус пишешь код. К тебе подходит тестировщик и говорит, что в календаре на сайте в 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, зачастую ошибаются и показывают неверные даты:
@DiMurer
карма
6,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (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 )
        • –1
          На 12:00
      • 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 и локальным временем в минутах) это будет настоящая ошибка.

                  Ошибка же в представлении данных есть, но даже если числа будут в стиле хищника вряд ли можно считать её критичной. В отличии от хранимой даты.
  • +1
  • 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 который нужно применить до загрузки каких либо скриптов работающих с датой и временем. При этом отпадет необходимость делать правки в старых скриптах.

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