Während meiner jüngsten Erfahrung beim Schreiben eines JS-Dolmetschers habe ich mich intensiv mit dem Innenleben von ECMA / JS-Daten auseinandergesetzt. Also werde ich hier meine 2 Cent einwerfen. Hoffentlich hilft das Teilen dieses Materials anderen bei Fragen zu den Unterschieden zwischen Browsern im Umgang mit Datumsangaben.
Die Eingangsseite
Alle Implementierungen speichern ihre Datumswerte intern als 64-Bit-Zahlen, die die Anzahl der Millisekunden (ms) seit 1970-01-01 UTC darstellen (GMT ist dasselbe wie UTC). Dieses Datum ist die ECMAScript-Epoche, die auch von anderen Sprachen wie Java und POSIX-Systemen wie UNIX verwendet wird. Daten, die nach der Epoche auftreten, sind positive Zahlen und Daten vor der Epoche sind negativ.
Der folgende Code wird in allen aktuellen Browsern als dasselbe Datum interpretiert, jedoch mit dem lokalen Zeitzonenversatz:
Date.parse('1/1/1970'); // 1 January, 1970
In meiner Zeitzone (EST, -05: 00) ist das Ergebnis 18000000, da so viele ms in 5 Stunden sind (in den Sommermonaten sind es nur 4 Stunden). Der Wert ist in verschiedenen Zeitzonen unterschiedlich. Dieses Verhalten wird in ECMA-262 angegeben, sodass alle Browser es auf die gleiche Weise tun.
Zwar gibt es einige Abweichungen bei den Eingabezeichenfolgenformaten, die von den wichtigsten Browsern als Datumsangaben analysiert werden, sie interpretieren sie jedoch im Wesentlichen in Bezug auf Zeitzonen und Sommerzeit gleich, obwohl die Analyse weitgehend von der Implementierung abhängt.
Das ISO 8601-Format unterscheidet sich jedoch. Dies ist eines von nur zwei in ECMAScript 2015 (ed 6) beschriebenen Formaten, die von allen Implementierungen auf die gleiche Weise analysiert werden müssen (das andere ist das für Date.prototype.toString angegebene Format ).
Aber selbst für Zeichenfolgen im ISO 8601-Format ist bei einigen Implementierungen ein Fehler aufgetreten. Hier ist eine Vergleichsausgabe von Chrome und Firefox, als diese Antwort ursprünglich für den 1.1.1970 (die Epoche) auf meinem Computer mit Zeichenfolgen im ISO 8601-Format geschrieben wurde, die in allen Implementierungen auf genau denselben Wert analysiert werden sollten :
Date.parse('1970-01-01T00:00:00Z'); // Chrome: 0 FF: 0
Date.parse('1970-01-01T00:00:00-0500'); // Chrome: 18000000 FF: 18000000
Date.parse('1970-01-01T00:00:00'); // Chrome: 0 FF: 18000000
- Im ersten Fall zeigt der "Z" -Spezifizierer an, dass sich die Eingabe in UTC-Zeit befindet, also nicht von der Epoche versetzt ist und das Ergebnis 0 ist
- Im zweiten Fall gibt der Bezeichner "-0500" an, dass sich die Eingabe in GMT-05: 00 befindet und beide Browser die Eingabe als in der Zeitzone -05: 00 interpretierend interpretieren. Dies bedeutet, dass der UTC-Wert von der Epoche versetzt ist, was bedeutet, dass dem internen Zeitwert des Datums 18000000 ms hinzugefügt werden.
- Der dritte Fall, in dem kein Spezifizierer vorhanden ist, sollte für das Hostsystem als lokal behandelt werden. FF behandelt die Eingabe korrekt als Ortszeit, während Chrome sie als UTC behandelt, wodurch unterschiedliche Zeitwerte erzeugt werden. Für mich ergibt sich ein Unterschied von 5 Stunden im gespeicherten Wert, was problematisch ist. Andere Systeme mit unterschiedlichen Offsets erzielen unterschiedliche Ergebnisse.
Dieser Unterschied wurde ab 2020 behoben, aber beim Parsen von Zeichenfolgen im ISO 8601-Format bestehen zwischen den Browsern andere Besonderheiten.
Aber es wird schlimmer. Eine Besonderheit von ECMA-262 ist, dass das Nur-Datum-Format nach ISO 8601 (JJJJ-MM-TT) als UTC analysiert werden muss, während es nach ISO 8601 als lokal analysiert werden muss. Hier ist die Ausgabe von FF mit den langen und kurzen ISO-Datumsformaten ohne Zeitzonenspezifizierer.
Date.parse('1970-01-01T00:00:00'); // 18000000
Date.parse('1970-01-01'); // 0
Der erste wird als lokal analysiert, da es sich um Datum und Uhrzeit nach ISO 8601 ohne Zeitzone handelt, und der zweite wird als UTC analysiert, da es sich nur um das Datum nach ISO 8601 handelt.
Um die ursprüngliche Frage direkt zu beantworten, "YYYY-MM-DD"
muss ECMA-262 als UTC interpretiert werden, während die andere als lokal interpretiert wird. Deshalb:
Dies führt nicht zu gleichwertigen Ergebnissen:
console.log(new Date(Date.parse("Jul 8, 2005")).toString()); // Local
console.log(new Date(Date.parse("2005-07-08")).toString()); // UTC
Das macht:
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());
Unter dem Strich werden Datumszeichenfolgen analysiert. Die EINZIGE ISO 8601-Zeichenfolge, die Sie sicher über Browser hinweg analysieren können, ist die lange Form mit einem Versatz (entweder ± HH: mm oder "Z"). Wenn Sie dies tun, können Sie sicher zwischen lokaler und UTC-Zeit hin und her gehen.
Dies funktioniert in allen Browsern (nach IE9):
console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());
Die meisten aktuellen Browser behandeln die anderen Eingabeformate gleich, einschließlich der häufig verwendeten Formate "01.01.1970" (M / T / JJJJ) und "01.01.1970 00:00:00" (M / T / JJJJ hh) : mm: ss ap) Formate. Alle folgenden Formate (mit Ausnahme des letzten) werden in allen Browsern als Ortszeiteingabe behandelt. Die Ausgabe dieses Codes ist in allen Browsern in meiner Zeitzone gleich. Der letzte wird unabhängig von der Host-Zeitzone als -05: 00 behandelt, da der Offset im Zeitstempel festgelegt ist:
console.log(Date.parse("1/1/1970"));
console.log(Date.parse("1/1/1970 12:00:00 AM"));
console.log(Date.parse("Thu Jan 01 1970"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00 GMT-0500"));
Da das Parsen selbst der in ECMA-262 angegebenen Formate nicht konsistent ist, wird empfohlen, sich niemals auf den integrierten Parser zu verlassen und Zeichenfolgen immer manuell zu analysieren, z. B. mithilfe einer Bibliothek, und das Format dem Parser bereitzustellen.
ZB in moment.js könnten Sie schreiben:
let m = moment('1/1/1970', 'M/D/YYYY');
Die Ausgangsseite
Auf der Ausgabeseite übersetzen alle Browser Zeitzonen auf dieselbe Weise, behandeln die Zeichenfolgenformate jedoch unterschiedlich. Hier sind die toString
Funktionen und was sie ausgeben. Beachten Sie die toUTCString
und toISOString
Funktionen, die 5:00 Uhr morgens auf meinem Computer ausgegeben werden. Der Zeitzonenname kann auch eine Abkürzung sein und in verschiedenen Implementierungen unterschiedlich sein.
Konvertiert vor dem Drucken von UTC in Ortszeit
- toString
- toDateString
- toTimeString
- toLocaleString
- toLocaleDateString
- toLocaleTimeString
Druckt die gespeicherte UTC-Zeit direkt
- toUTCString
- toISOString
In Chrome
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-05:00 (Eastern Standard Time)
toLocaleString 1/1/1970 12:00:00 AM
toLocaleDateString 1/1/1970
toLocaleTimeString 00:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
In Firefox
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-0500 (Eastern Standard Time)
toLocaleString Thursday, January 01, 1970 12:00:00 AM
toLocaleDateString Thursday, January 01, 1970
toLocaleTimeString 12:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
Normalerweise verwende ich das ISO-Format nicht für die Eingabe von Zeichenfolgen. Die Verwendung dieses Formats ist für mich nur dann von Vorteil, wenn Datumsangaben als Zeichenfolgen sortiert werden müssen. Das ISO-Format kann unverändert sortiert werden, die anderen nicht. Wenn Sie browserübergreifend kompatibel sein müssen, geben Sie entweder die Zeitzone an oder verwenden Sie ein kompatibles Zeichenfolgenformat.
Der Code new Date('12/4/2013').toString()
durchläuft die folgende interne Pseudotransformation:
"12/4/2013" -> toUCT -> [storage] -> toLocal -> print "12/4/2013"
Ich hoffe diese Antwort war hilfreich.