Подтвердить что ты не робот

Конструктор даты: числовые аргументы против аргумента строки, дающие разные даты в некоторых случаях

Прежде всего, я думаю, что часовой пояс, вероятно, имеет какое-то отношение к этому. Я в EST/EDT. Кроме того, я тестирую это на chromium 17/linux.

Теперь, допустим, я создаю две даты:

// December 5

dateFromNumbers = new Date(2020, 11, 5);
dateFromString = new Date("2020-12-5");

Кажется, эти даты должны иметь идентичные метки времени, и они:

+dateFromNumbers == +dateFromString; // true

... по крайней мере в этом случае. Но в некоторых случаях они не делают:

// December 15

dateFromNumbers = new Date(2020, 11, 15);
dateFromString = new Date("2020-12-15");

+dateFromNumbers == +dateFromString; // false

Что здесь происходит?

dateFromNumbers; // Tue Dec 15 2020 00:00:00 GMT-0500 (EST)
dateFromString;  // Mon Dec 14 2020 19:00:00 GMT-0500 (EST)

Похоже, dateFromString на 5 часов раньше dateFromNumbers в этом случае (EST - GMT-5, я уверен, что это так или иначе связано).

Кажется, что это касается концов месяцев с октября по декабрь. Здесь есть скрипка, которая позволяет легко видеть, в какие дни различаются (если вы не красно-зелёный дальтонизм, в этом случае это может быть трудно увидеть, мои извинения).

http://jsfiddle.net/9gBfX/

Что дает?


Примечания:

  • Вы можете настроить системный часовой пояс на EST/EDT, чтобы увидеть пример jsfiddle, как я его вижу.
  • Цифры с датами месяца основаны на нулевом значении; 11 не является опечаткой.
  • Эта проблема появляется каждый год, который я проверил.
4b9b3361

Ответ 1

После просмотра исходного кода V8:

// Specification:
// Accept ES5 ISO 8601 date-time-strings or legacy dates compatible
// with Safari.
<...>
//  A string that matches both formats (e.g. 1970-01-01) will be
//  parsed as an ES5 date-time string - which means it will default
//  to UTC time-zone. That unavoidable if following the ES5
//  specification.

Считывая окружающий код, кажется, что строка с датой и длиной месяца и дня 2 считается действительной строкой даты ES5. Далее в парсер ES5, после того, как он анализирует даты и время, есть комментарий:

// Successfully parsed ES5 Date Time String. Default to UTC if no TZ given.

В случае "YYYY-MM-DD", как только код дойдет до конца, парсер ES5 успешно проанализировал всю строку, поэтому он возвращается до того, как устаревший парсер получит возможность локализовать часовой пояс. В противном случае (месяц/день - один символ длинный) он рассматривался как "наследие" datetime, и анализирующий парсер получает возможность разобраться с ним и локализовать его.

Ответ 2

Здесь приведен упрощенный ответ из других ответов.

Дата распознает различные форматы строк

  • Нестандартные даты
  • RFC 2282 даты
  • ES 5 дат

Большинство форматов интерпретируются как локальные даты

На странице 14 RFC 2282 мы видим:

Дата и время суток ДОЛЖНЫ выражать местное время.

Нестандартные даты обрабатываются аналогичным образом.

Формат ES 5 интерпретируется как UTC

В разделе 15.9.1.15 спецификации ES 5 мы видим:

Значение смещения отсутствующего часового пояса - "Z".

"Z" обозначает время UTC.

Десятая октября

Отформатированные даты ES 5 требуют двухзначных месяцев и дней. Месяцы и дни в исходном сообщении не имеют нулевой пробел. "2020-9-9" не является действительным представлением даты ES 5; это нестандартный формат, поэтому он интерпретируется по местному времени. "2020-10-10" является действительным представлением даты ES 5, поэтому его необходимо интерпретировать в формате UTC.

Возможные обходные пути

  • Не используйте конструктор строк /Date.parse!
  • Измените символ разделителя, чтобы формат никогда не соответствовал формату ES 5.
  • Укажите часовой пояс.
  • Отрегулируйте даты по местному времени. Если у них есть часы или минуты: date.setMinutes(date.getTimezoneOffset()); (похоже, это все равно работает).

Ответ 3

Использование "-" в качестве разделителя дат для дат США смущает некоторые браузеры, некоторые будут выполнять арифметику даты, другие вернут NaN, поэтому используйте разделитель дат "/". Решением, поддерживающим культуру, является использование date.js, который является выдающимся обработчиком даты JavaScript, который разрешает проблемы, подобные тем, которые вы указали (http://www.datejs.com/). Использование метода parse устраняет всю путаницу:

Date.parse("2020-12-15").toString() // yields the correct date ("Tue Dec 15 00:00:00 PST 2020"). 

Ответ 4

ретрансляция на этом сообщении, кажется, что конструктор строковых аргументов Date чувствителен к реализации из-за различных реализаций Date.parse() браузерами.

ваши измерения верны, и вам, вероятно, следует избегать использования этого конструктора в целом, если вы хотите, чтобы ваш браузер правильно разбирал EST.

Ответ 5

Похоже, что конструктор даты требует пробелов, а не '-'. Это рекомендуемый способ. Проверьте эту ссылку:
3.3. Спецификация даты и времени

Хотя складчатое белое пространство разрешено на протяжении всего времени спецификации, РЕКОМЕНДОВАНО, что одно пространство используется в каждое место, которое появляется FWS (требуется ли оно или необязательно)

Также ознакомьтесь с этой ссылкой:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date

dateString: значение строки, представляющее дату. Строка должна быть в формат, распознаваемый методом анализа (IETF-совместимый RFC 2822 метки времени).

Я пробовал следующий код, и он возвращает true

dateFromNumbers = new Date(2020, 11, 15);
dateFromString = new Date("2020 12 15");
alert(+dateFromNumbers == +dateFromString);​

И это не проблема, начинающаяся с октября месяца, это связано с двузначными месяцами. Если я попробую тот же метод с сентября, то:

dateFromNumbers = new Date(2020, 8, 15);
dateFromString = new Date("2020-09-15");
alert(+dateFromNumbers == +dateFromString);​ // This returns false

Но если я использую одну цифру для сентября, тогда она возвращает true

dateFromNumbers = new Date(2020, 8, 15);
dateFromString = new Date("2020-9-15");
alert(+dateFromNumbers == +dateFromString);​ // This returns true

И если использовать пробел с двойной цифрой сентябрь, тогда он возвращает true

dateFromNumbers = new Date(2020, 8, 15);
dateFromString = new Date("2020 09 15");
alert(+dateFromNumbers == +dateFromString);​//This returns true