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