Чому "2016-02-16" не дорівнює "2016-02-16 00:00"?


96

Я намагаюся передати обидва рядки дати new Date(t).

Я думаю, що обидва рядки представляють один і той же час, зрештою, якщо я пропускаю час, чи не повинна це бути опівночі цього дня?

Але поки,

new Date("2016-02-16 00:00")

повертається 2016-02-16, опівночі, місцевий час, як очікувалося,

new Date("2016-02-16")

повертає 16.02.2016, опівночі UTC, що неправильно, або, принаймні, не те, що я очікував, враховуючи те, що аналізує інший рядок.

Я б зрозумів це, як би вони обидва мали однакову поведінку, чи повертати час як місцевий час, або як UTC, але здається дуже непослідовними, чому вони повертають різні речі, як це.

Як вирішення, коли я зустрічаю побачення, яке не має відповідної часової позначки, я можу додати "00:00", щоб отримати послідовну поведінку, але здається, що це досить неміцно.

Я отримую це значення з елемента INPUT типу "datetime-local", тому особливо непослідовним є те, що мені потрібно обійти значення, повернене елементом сторінки.

Чи я щось роблю неправильно, чи повинен щось робити інакше?


2
2016-02-16 00:00- це зовсім не схоже на дійсний час. ecma-international.org/ecma-262/6.0/… , але навіть після того, як ви помістите Tтуди, він дійсно поводиться інакше
zerkms

Як саме ви зараз отримуєте об’єкт Date від вхідного елемента на основі його значення?
BoltClock

4
Відповідно до стандарту - "Якщо поля HH, mm або ss відсутні" 00 "використовується як значення, а значення відсутнього поля sss -" 000 ". Якщо зміщення часового поясу відсутнє, дата-час трактується як місцевий час ". --- вона повинна поводитись так само.
zerkms

@BoltClock Хм, схоже на те, що він приймає поле значення елемента та (як помітили zerkms) чомусь видаляє T (я думаю, оскільки значення відображається користувачеві в контексті, де "T" буде заплутаним)
Майкл

1
@Michael: Фантастичний. Надзвичайні вигляди браузера - це моя улюблена. (Або це може бути химерність специфікації DOM? Не маю ідеї, я насправді не дивився.)
BoltClock

Відповіді:


100

Це те, що говорить специфікація ES5.1 :

Значення відсутнього зміщення часового поясу - «Z».

Тут також сказано:

Функція спочатку намагається проаналізувати формат рядка згідно з правилами, зазначеними у форматі рядка дати та часу (15.9.1.15). Якщо рядок не відповідає цьому формату, функція може повернутися до будь-яких специфічних для реалізації евристик або форматів дат, конкретних для реалізації.

Оскільки для формату потрібен Tроздільник між датою та часом, дійсні часи переходять у UTC:

> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)

... в той час як у node.js недійсний час (без роздільника T), здається, переходить до реалізації конкретного localtime:

> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)

Зауважте, що ES6 змінив це в тій же частині документації, яку він змінює на:

Якщо зміщення часового поясу відсутнє, дата-час трактується як місцевий час.

Радість ламати зміни .

Редагувати

Відповідно до TC39 , специфікація призначена для інтерпретації як рядки дати та часу без часового поясу (наприклад, "2016-02-16T00: 00: 00") трактуються як локальні (згідно ISO 8601), але лише рядки дати (наприклад, "2016-02-16") як UTC (що не відповідає ISO 8601).


20
Радість зламати зміни, справді. У новому проекті стандарту ES7 частина зміни з UTC на місцевий час була повернена . Новий стандарт говорить, що дати слід інтерпретувати як UTC, якщо не вказано часовий пояс, тоді як дати-дати слід інтерпретувати як місцевий час, якщо немає часового поясу вказано.
hichris123

3
Вони дійсно повинні бути місцевим часом, незалежно від форм, які мають лише дату чи дати. Ось так працює ISO8601. Смішно, що форма лише для дати трактується як півночі UTC, оскільки позачасова дата UTC навіть не має сенсу концептуально. Про це були бурхливі дискусії на ECMA tc39. Я бився за місцевий час, і програв. github.com/tc39/ecma262/isissue/87
Метт Джонсон-

10

Відповідно до специфікацій :

Функція спочатку намагається проаналізувати формат рядка згідно з правилами, зазначеними у форматі рядка дати та часу (15.9.1.15). Якщо рядок не відповідає цьому формату, функція може повернутися до будь-яких специфічних для реалізації евристик або форматів дат, конкретних для реалізації.

Формати рядків часу і дати приймаються 2016-02-16як дійсна дата

Цей формат включає форми лише для дати:

РРРР
РРРР-ММ
РРРР-ММ-ДД

[...] Якщо поля HH, mm або ss відсутні, "00" використовується як значення, а значення відсутнього поля sss - "000". Значення відсутнього зміщення часового поясу - «Z».

Таким чином 2016-02-16перекладається на 2016-02-16T00:00:00.000Z.

Інша дата 2016-02-16 00:00не відповідає формату, і тому її розбір є специфічним для реалізації. Мабуть, такі дати трактуються як локальний часовий пояс, і ваша прикладна дата поверне різні значення залежно від часового поясу:

/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z

Підсумок:

  • Для відповідності форматів часу дати поведінка добре визначена - за відсутності зміщення часового поясу рядок дати трактується як UTC (ES5) або локальний (ES6).
  • Для невідповідних форматів часу дати поведінка є специфічною для впровадження - за відсутності зрушення часового поясу звичайною поведінкою є трактування дати як місцевої.
  • Власне кажучи, реалізація може обрати для повернення NaNзамість того, щоб намагатися проаналізувати невідповідні дати. Просто протестуйте свій код в Internet Explorer 11;)

7

Можливо, ви стикаєтеся з різницею між реалізаціями ES5, ES6 та очікуваним результатом. На Date.parse в MDN, "особливо в різних реалізаціях ECMAScript, де рядки типу" 2015-10-12 12:00:00 "можуть бути проаналізовані як NaN, UTC або локальний часовий пояс" є значущими.

Додаткове тестування в Firefox 44 та IE 11 виявило, що вони обидва повертають об'єкт дати, для new Date("2016-02-16 00:00")якого об’єкт повертає NaN при спробі отримати значення компонента дати, а значення toString - "Недійсна дата" (не "NaN"). Отже, додавання "00:00 для послідовної поведінки" може легко працювати в різних браузерах.

Як зазначено в інших відповідях, new Date("2016-02-16")за замовчуванням використовується зсув часового поясу нуля, виробляючи опівночі UTC замість локального.


Здається, OP отримує різні результати щодо одного впровадження.
Салман

6

Відповідно DateParser::Parse()до вихідних кодів V8 для Chrome.

Дати ES5 ISO 8601:

[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]

Непідписане число, яке супроводжується символом ":", є часовим значенням і додається до TimeComposer.

за промовчанням часового поясу Z, якщо його немає

> new Date("2016-02-16 00:00")
  Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)

Рядок, що відповідає обом форматам (наприклад 1970-01-01), буде проаналізований як рядок дати-часу ES5 - це означає, що вона буде за замовчуванням UTC time-zone. Цього не уникнути, якщо дотримуватися специфікації ES5.

> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)

3

повертає 16.02.2016, опівночі UTC, що неправильно, або, принаймні, не те, що я очікував, враховуючи те, що аналізує інший рядок.

Це додає зміщення часового поясу до 00:00

new Date("2016-02-16") виходи Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)

Мій часовий пояс був IST зі зміщеним значенням (у хвилинах) +330, тому він додав 330 хвилин до 00:00.

Відповідно до ecma-262, розділ 20.3.3.2. Дата.параметр (рядок)

Якщо ToString призводить до несподіваного завершення, запис про завершення негайно повертається. В іншому випадку синтаксичний аналіз інтерпретує отриманий рядок як дату та час; він повертає число, значення часу UTC, яке відповідає даті та часу. Рядок може інтерпретуватися як локальний час, час UTC або час у якомусь іншому часовому поясі, залежно від вмісту рядка.

Коли ви чітко встановите одиниці часу, new Date("2016-02-16 00:00")вони будуть використовувати такі, як hoursі minutes,

Інакше, як зазначено тут у 2 0.3.1.16

Якщо зміщення часового поясу відсутнє, дата-час трактується як місцевий час.


Так, але чому це робиться в одному випадку, а не в іншому?
Майкл

@Michael так, перевірте ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf section 20.3.3.2
gurvinder372

То чому це різні результати? Стандарт стверджує, що він повинен бути таким же
zerkms

@zerkms Standard каже, що буде робити, коли ви передасте одиниці часу, він не говорить, що буде робити, коли ви цього не зробите. Це чітко говорить, The String may be interpreted as a local time, a UTC time, or a time in some other time zone, depending on the contents of the String.де це твердження, що воно повинно бути таким же?
gurvinder372

@ gurvinder372 Я вказав цитату у коментарях до запитання: "Якщо поля HH, mm або ss відсутні," 00 "використовується як значення, а значення відсутнього поля sss -" 000 ". Якщо часовий пояс зміщено відсутня, дата-час трактується як місцевий час ".
zerkms
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.