Perché "2016-02-16" non è uguale a "2016-02-16 00:00"?


96

Sto cercando di passare entrambe le stringhe di data a new Date(t).

Mi aspetto che entrambe le stringhe rappresentino la stessa ora, dopotutto, se ometto l'ora, non dovrebbe essere la mezzanotte di quel giorno?

Ma mentre,

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

restituisce 2016-02-16, mezzanotte, ora locale come previsto,

new Date("2016-02-16")

restituisce 2016-02-16, mezzanotte UTC, che è sbagliato, o almeno non è quello che mi aspettavo visto come viene analizzata l'altra stringa.

Lo capirei se entrambi avessero lo stesso comportamento, sia che si tratti di restituire l'ora come ora locale o come UTC, ma sembra molto incoerente il motivo per cui restituiscono cose diverse come questa.

Come soluzione alternativa, ogni volta che incontro una data che non ha un timestamp corrispondente, posso aggiungere "00:00" per ottenere un comportamento coerente, ma sembra che sia piuttosto fragile.

Sto ottenendo questo valore da un elemento INPUT, di tipo "datetime-local", quindi sembra particolarmente incoerente che devo aggirare un valore restituito da un elemento di pagina.

Sto facendo qualcosa di sbagliato o dovrei fare qualcosa di diverso?


2
2016-02-16 00:00- questo non sembra affatto l'ora valida. ecma-international.org/ecma-262/6.0/… , ma anche dopo averlo inserito Tsi comporta effettivamente in modo diverso
zerkms

In che modo esattamente stai ottenendo attualmente l'oggetto Date dall'elemento di input in base al suo valore?
BoltClock

4
Come da standard: "Se i campi HH, mm o ss sono assenti" 00 "viene utilizzato come valore e il valore di un campo sss assente è" 000 ". Se lo scostamento del fuso orario è assente, la data-ora viene interpretato come ora locale. " --- dovrebbe comportarsi allo stesso modo.
zerkms

@BoltClock Hmm, sembra che stia prendendo il campo del valore dell'elemento e (come hanno notato zerkms) rimuovendo la T per qualche motivo (penso perché il valore viene visualizzato all'utente in un contesto in cui "T" sarebbe fonte di confusione)
Michael

1
@Michael: fantastico. Le stranezze del browser come questa sono le mie preferite. (O potrebbe essere una stranezza delle specifiche DOM? Non ne ho idea, non ho davvero guardato.)
BoltClock

Risposte:


100

È ciò che la specifica ES5.1 dice di fare:

Il valore di una differenza di fuso orario assente è "Z".

Dice anche:

La funzione prima tenta di analizzare il formato della stringa in base alle regole chiamate in Formato stringa data ora (15.9.1.15). Se la stringa non è conforme a quel formato, la funzione può ricorrere a qualsiasi euristica specifica dell'implementazione o formati di data specifici dell'implementazione.

Poiché il formato richiede un Tseparatore tra data e ora, l'ora valida va a 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)

... mentre in node.js, un tempo non valido (senza il separatore T) sembra andare al localtime specifico dell'implementazione:

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

Nota che ES6 ha cambiato questo, nella stessa parte della documentazione cambia in:

Se la differenza di fuso orario è assente, la data e l'ora viene interpretata come ora locale.

La gioia di rompere i cambiamenti .

modificare

Secondo TC39 , la specifica deve essere interpretata come stringhe di data e ora senza un fuso orario (ad es. "2016-02-16T00: 00: 00") vengono trattate come locali (per ISO 8601), ma le stringhe di sole date (ad es. "2016-02-16") come UTC (che non è coerente con ISO 8601).


20
La gioia di rompere cambia, davvero. In una nuova bozza dello standard ES7, parte del cambiamento dall'ora UTC all'ora localeèstata annullata Il nuovo standard dice che le date dovrebbero essere interpretate come UTC se nonèspecificato un fuso orario, mentre le date-ora dovrebbero essere interpretate come ora locale se non c'è fuso orario è specificato.
hichris123

3
Dovrebbero essere entrambe l'ora locale, indipendentemente dai moduli di sola data o data-ora. È così che funziona ISO8601. È ridicolo che la forma di sola data sia interpretata come mezzanotte UTC, poiché una data senza tempo UTC non ha nemmeno senso concettualmente. C'è stato un acceso dibattito su questo all'ECMA tc39. Ho lottato per l'ora locale e ho perso. github.com/tc39/ecma262/issues/87
Matt Johnson-Pint

10

Secondo le specifiche :

La funzione prima tenta di analizzare il formato della stringa in base alle regole chiamate in Formato stringa data ora (15.9.1.15). Se la stringa non è conforme a quel formato, la funzione può ricorrere a qualsiasi euristica specifica dell'implementazione o formati di data specifici dell'implementazione.

E i formati stringa data e ora accettano 2016-02-16come data valida

Questo formato include moduli di sola data:

AAAA
AAAA-MM
AAAA-MM-GG

[...] Se i campi HH, mm o ss sono assenti, viene utilizzato "00" come valore e il valore di un campo sss assente è "000". Il valore di una differenza di fuso orario assente è "Z".

Quindi si 2016-02-16traduce in 2016-02-16T00:00:00.000Z.

L'altra data 2016-02-16 00:00non è conforme al formato e pertanto la sua analisi è specifica dell'implementazione. Apparentemente, tali date vengono trattate come se avessero fuso orario locale e la data di esempio restituirà valori diversi a seconda del fuso orario:

/* 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

Sommario:

  • Per formati di data e ora conformi, il comportamento è ben definito: in assenza di offset del fuso orario, la stringa della data viene trattata come UTC (ES5) o locale (ES6).
  • Per i formati di data e ora non conformi, il comportamento è specifico dell'implementazione: in assenza di offset del fuso orario, il comportamento usuale è trattare la data come locale.
  • È un dato di fatto, l'implementazione potrebbe scegliere di tornare NaNinvece di cercare di analizzare date non conformi. Basta testare il codice in Internet Explorer 11;)

7

Forse stai riscontrando differenze tra le implementazioni ES5, ES6 e il risultato atteso. Per Date.parse su MDN, "soprattutto tra diverse implementazioni ECMAScript in cui stringhe come" 2015-10-12 12:00:00 "possono essere analizzate come NaN, UTC o fuso orario locale" è significativo.

Ulteriori test in Firefox 44 e IE 11 hanno rivelato che entrambi restituiscono un oggetto data per new Date("2016-02-16 00:00"), quale oggetto restituisce NaN quando si tenta di ottenere un valore del componente data e il cui valore toString è "Data non valida" (non "NaN"). Quindi l'aggiunta di "00:00 per ottenere un comportamento coerente" può facilmente interrompersi in browser diversi.

Come notato in altre risposte new Date("2016-02-16")utilizza un offset di fuso orario pari a zero per impostazione predefinita, producendo mezzanotte UTC anziché locale.


OP sembra ottenere risultati diversi sulla stessa implementazione.
Salman A

6

Per DateParser::Parse()dei codici sorgente V8 per Chrome.

Date ES5 ISO 8601:

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

Un numero senza segno seguito da ":" è un valore temporale e viene aggiunto a TimeComposer.

il fuso orario predefinito è Z se mancante

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

Una stringa che corrisponde a entrambi i formati (ad es. 1970-01-01) Verrà analizzata come una stringa data-ora ES5, il che significa che verrà impostata su UTC time-zone. Ciò è inevitabile se si seguono le specifiche ES5.

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

3

restituisce 2016-02-16, mezzanotte UTC, che è sbagliato, o almeno non è quello che mi aspettavo visto come viene analizzata l'altra stringa.

Aggiunge lo scostamento del fuso orario al file 00:00

new Date("2016-02-16") uscite Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)

Il mio fuso orario è IST con un valore di offset (in minuti) +330, quindi ha aggiunto 330 minuti a 00:00.

Secondo ecma-262, sezione 20.3.3.2 Date.parse (stringa)

Se ToString risulta in un completamento improvviso, viene immediatamente restituito il record di completamento. Altrimenti, parse interpreta la stringa risultante come data e ora; restituisce un numero, il valore dell'ora UTC corrispondente alla data e all'ora. La stringa può essere interpretata come un'ora locale, un'ora UTC o un'ora in un altro fuso orario, a seconda del contenuto della stringa.

Quando imposti esplicitamente le unità di tempo new Date("2016-02-16 00:00"), utilizzerà set that as hoursand minutes,

Altrimenti, come indicato qui in 2 0.3.1.16

Se la differenza di fuso orario è assente, la data e l'ora viene interpretata come ora locale.


Sì, ma perché lo fa in un caso ma non nell'altro?
Michael


Allora perché questi sono risultati diversi? Lo standard afferma che deve essere lo stesso
zerkms

@zerkms Standard dice cosa farà quando passi le unità di tempo, non dice cosa farà quando non lo farai tu. Dice chiaramente 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.dove afferma che deve essere lo stesso?
gurvinder372

@ gurvinder372 Ho fornito la citazione nei commenti alla domanda: "Se i campi HH, mm o ss sono assenti" 00 "viene utilizzato come valore e il valore di un campo sss assente è" 000 ". Se la differenza di fuso orario è assente, la data e l'ora viene interpretata come ora locale. "
zerkms
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.