В чем разница между новой датой ( "2017-01-01" ) и новой датой ( "2017-1-1" )?

Я ввожу new Date("2017-01-01") в хром-консоль, вывод показывает, что его час равен 8, но new Date("2017-01-1") и new Date("2017-1-01") показывает, что их час равен 0, поэтому как new Date(dateString) анализировать?

new Date("2017-01-01")
// Sun Jan 01 2017 08:00:00 GMT+0800 (中国标准时间)*
new Date("2017-01-1")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*
new Date("2017-1-1")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*
new Date("2017-1-01")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*

Ответ 1

"2017-01-01" следует стандарту ISO Формат даты ES5 Date Time String (упрощение формата ISO 8601 Extended), и, следовательно, это время UTC, которое составляет 8 часов в Китае. Все остальные строки анализируются как локальное время в Chrome 1.


1 Соответствующий исходный код в Chromium: https://cs.chromium.org/chromium/src/v8/src/dateparser-inl.h?type=cs&l=16

Анализ даты в Chromium соответствует стандартным правилам ES5, а также этим дополнительным правилам:

  • Любое нераспознанное слово перед первым числом игнорируется.
  • Воспроизведение в скобках игнорируется.
  • Беззнаковое число, за которым следует :, является значением времени и добавляется к TimeComposer. Число, за которым следует ::, добавляет второй нуль. Число, за которым следует ., также является временем и должно сопровождаться миллисекундами. Любое другое число является компонентом даты и добавляется к DayComposer.
  • Название месяца (или действительно: любое слово, имеющее те же первые три буквы, что и имя месяца) записывается как именованный месяц в композиторе Day.
  • Слово, распознаваемое как временная зона, записывается как таковое, как (+|-)(hhmm|hh:).
  • Даты устаревших не допускают дополнительных знаков (+ или -) или несопоставимых ) после того, как номер был прочитан (перед первым номером разрешен любой мусор).
  • Любые строки, которые удовлетворяют правилам ES5 и правилам выше, будут проанализированы с использованием правил ES5. Это означает, что "1970-01-01" будет в часовом поясе UTC не в локальной часовой зоне.

Что это значит?

Сначала обратите внимание, что "2017-01-01" анализируется в UTC, потому что это строка "date" вместо строки "date-time" и соответствует определению ES5 строки "date". Если время присоединено, то оно будет следовать стандарту ISO и проанализировать его по местному времени.

Примеры:

  • 2017-01-01 - 1 января 2017 года в UTC
  • 2017-01-01T00:00 - 1 января 2017 года по местному времени
  • 2017-1-1 - 1 января 2017 года по местному времени
  • 2017-(hello)01-01 - 1 января 2017 года по местному времени
  • may 2017-01-01 - 1 мая 2017 года по местному времени
  • mayoooo 2017-01-01 - 1 мая 2017 года по местному времени
  • "jan2017feb-mar01apr-may01jun" - 1 июня 2017 года по местному времени

Ответ 2

разница между новой датой ( "2017-01-01" ) и новой датой ( "2017-1-1" )

new Date("2017-01-01") находится в спецификации (подробнее см. ниже). new Date("2017-1-1") нет, и поэтому возвращается к любой "... специфичной для реализации эвристике или конкретным форматам дат реализации", которые хочет применить механизм JavaScript. Например, у вас нет гарантии того, как (или будет) он будет успешно разбираться, и если да, будет ли он проанализирован как UTC или местное время.

Хотя new Date("2017-01-01") находится в спецификации, к сожалению, что браузеры должны делать с ним, это была движущаяся цель, потому что на нем нет индикатора часового пояса:

  • В ES5 (декабрь 2009 г.) строки без индикатора часового пояса должны анализироваться как UTC. Но в отличие от стандарта ISO-8601 основан формат даты и времени, в котором говорится, что строки без индикатора часового пояса предназначены для локального времени, а не для UTC. Таким образом, в ES5, new Date("2017-01-01") анализируется в UTC.
  • В ES2015 (ака ES6, июнь 2015 г.) строки без индикатора часового пояса должны были быть локальным временем, а не UTC, например, ISO -8601. Итак, в ES2015, new Date("2017-01-01") анализируется как локальное время.
  • Но, который был снова изменен в ES2016 (июнь 2016 г.), поскольку браузеры анализировали только даты формы с - в них как UTC в течение многих лет. Так, как и в ES2016, форматы только для даты (например, "2017-01-01") анализируются в формате UTC, но формы даты/времени (например, "2017-01-01T00:00:00") анализируются по местному времени.

К сожалению, не все механизмы JavaScript в настоящее время реализуют спецификацию. Chrome (начиная с этой записи, v56) анализирует формы даты/времени в формате UTC, хотя они должны быть локальными (так же как и IE9). Но Chrome, Firefox и IE11 (у меня нет IE10 или Edge), все обрабатываются только форматы даты (в формате UTC). IE8 вообще не реализует форму ISO-8601 (был выпущен до выпуска спецификации ES5).

Ответ 3

При анализе дат JavaScript интерпретирует даты ISO как время UTC и другие форматы как локальное время.

Как Статья MDN предлагает

Если строка имеет только дату ISO 8601, для интерпретации аргументов используется часовой пояс UTC.

Учитывая строку даты "7 марта 2014 года", parse() принимает локальный часовой пояс, , но с учетом формата ISO, такого как "2014-03-07", он примет часовой пояс UTC ( ES5 и ECMAScript 2015). Поэтому объекты Date, созданные с использованием этих строк, могут представлять разные моменты времени в зависимости от версии поддерживаемой ECMAScript, если система не установлена ​​с локальным часовым поясом UTC. Это означает, что две строки даты, которые эквивалентны, могут приводить к двум различным значениям в зависимости от формата преобразуемой строки.

// 2017-03-28 is interpreted as UTC time,
// shown as 2017-03-28 00:00:00 in UTC timezone,
// shown as 2017-03-28 06:00:00 in my timezone:
console.log("ISO dates:");
var isoDates = [new Date("2017-03-28")];
for (var dt of isoDates)
{
  console.log(dt.toUTCString() + " / " + dt.toLocaleString());
}

// Other formats are interpreted as local time, 
// shown as 2017-03-27 18:00:00 in my timezone,
// shown 2017-03-28 00:00:00 in my timezone:
console.log("Other formats:");
var otherDates = [new Date("2017-3-28"), new Date("March 28, 2017"), new Date("2017/03/28")];
for (var dt of otherDates)
{
  console.log(dt.toUTCString() + " / " + dt.toLocaleString());
}

Ответ 4

Этот формат является международным стандартом (формат ISO)

new Date("2017-01-01")

Это гарантирует одинаковый вывод во всех браузерах.

Однако другие форматы могут изменяться в зависимости от браузера, поскольку они не так четко определены.

Как вы можете видеть, этот формат

new Date("2017-1-1")

успешно разбирается в chrome, но дает ошибку в IE 11