new Date(Date.parse("Jul 8, 2005"));
Fri Jul 08 2005 00:00:00 GMT-0700 (PST)
new Date(Date.parse("2005-07-08"));
Do 07 Jul 2005 17:00:00 GMT-0700 (PST)
Warum ist die zweite Analyse falsch?
Bis zum Erscheinen der 5. Auflage war die Methode Date.parse
vollständig implementierungsabhängig (new Date(string)
ist äquivalent zu Date.parse(string)
, es sei denn, letztere gibt eine Zahl statt einer Date
zurück). In der 5. Ausgabe der Spezifikation wurde die Anforderung hinzugefügt, um ein vereinfachtes (und etwas falsch) zu unterstützen ISO-8601 (siehe auch Was sind gültige Datums-Zeitzeichenfolgen in JavaScript? ). Ansonsten gab es no, was Date.parse
new Date(string)
akzeptieren sollte, außer dass sie die _/Date # toString -Ausgabe akzeptieren mussten (ohne zu sagen, was das war).
Ab ECMAScript 2017 (Ausgabe 8) mussten Implementierungen ihre Ausgabe für Date # toString und Date # toUTCString parsen, das Format dieser Zeichenfolgen wurde jedoch nicht angegeben.
Ab ECMAScript 2019 (Ausgabe 9) wurde das Format für Date # toString und Date # toUTCString als (jeweils) angegeben:
bereitstellung von 2 weiteren Formaten, die Date.parse zuverlässig in neuen Implementierungen analysieren sollte (wobei zu beachten ist, dass die Unterstützung nicht allgegenwärtig ist und nichtkonforme Implementierungen noch einige Zeit verwendet werden).
Ich würde empfehlen, Datumsstrings manuell zu analysieren und den Date-Konstruktor mit Argumenten für Jahr, Monat und Tag zu verwenden, um Mehrdeutigkeiten zu vermeiden:
// parse a date in yyyy-mm-dd format
function parseDate(input) {
var parts = input.split('-');
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}
Während ich kürzlich einen JS-Dolmetscher geschrieben habe, habe ich mich intensiv mit den inneren Abläufen von ECMA/JS-Dates auseinandergesetzt. Ich denke, ich werde hier meine 2 Cent einwerfen. Wir hoffen, dass das Teilen dieser Informationen anderen bei Fragen zu den Unterschieden zwischen Browsern beim Umgang mit Datumsangaben helfen kann.
Alle Implementierungen speichern ihre Datumswerte intern als 64-Bit-Zahlen, die die Anzahl der Millisekunden seit dem 1.1.1970 UTC darstellen (GMT entspricht UTC). Daten, die nach 1/1/1970 00:00:00
vorkommen, sind positive Zahlen und frühere Daten sind negativ.
Daher erzeugt der folgende Code auf allen Browsern genau das gleiche Ergebnis.
Date.parse('1/1/1970');
In meiner Zeitzone (EST) ist das Ergebnis 18000000, da dies die Anzahl ms in 5 Stunden ist (in Sommermonaten sind es nur 4 Stunden). Der Wert ist in verschiedenen Zeitzonen unterschiedlich. Alle großen Browser machen es auf dieselbe Weise.
Hier ist das Problem. Zwar gibt es einige Abweichungen in den Eingabezeichenfolgenformaten, die von den wichtigsten Browsern als Datumsangaben geparst werden, sie werden jedoch in Bezug auf Zeitzonen und Sommerzeit im Wesentlichen gleich interpretiert. Das eine ist das ISO 8601-Format. Es ist das einzige Format, das speziell in der Spezifikation ECMA-262 v.5 beschrieben wird. Bei allen anderen String-Formaten ist die Interpretation implementierungsabhängig. Ironischerweise ist dies das Format, in dem sich Browser unterscheiden können. Hier ist eine Vergleichsausgabe von Chrome im Vergleich zu Firefox für 1/1/1970 auf meinem Rechner im ISO 8601-Stringformat.
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
toString
mit meinem Eingabewert übereinstimmt, es sei denn, ich gebe eine alternative Zeitzone an, die ich nie tue. Das abwesenheit eines Spezifizierers sollte die lokale Zeitangabe annehmen.Aber hier wird es schlimmer. FF behandelt die Kurzform des ISO 8601-Formats ("JJJJ-MM-TT") anders als die Langform ("JJJJ-MM-DDTHH: mm: ss: sssZ") Kein logischer Grund. Hier ist die Ausgabe von FF mit den langen und kurzen ISO-Datumsformaten ohne Zeitzonenangabe.
Date.parse('1970-01-01T00:00:00'); // 18000000
Date.parse('1970-01-01'); // 0
Um die Frage des ursprünglichen Fragestellers direkt zu beantworten, ist "YYYY-MM-DD"
die Kurzform des ISO 8601-Formats "YYYY-MM-DDTHH:mm:ss:sssZ"
. Es wird also als UTC-Zeit interpretiert, während der andere als lokal interpretiert wird. Deshalb,
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08")).toString());
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());
In der unteren Zeile werden Datumszeichenfolgen analysiert. Die EINZIGE ISO-8601-Zeichenfolge, die Sie sicher über Browser hinweg analysieren können, ist die lange Form. Verwenden Sie IMMER den Bezeichner "Z". Wenn Sie dies tun, können Sie sicher zwischen lokaler und UTC-Zeit hin und her wechseln.
console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());
Glücklicherweise behandeln die meisten aktuellen Browser die anderen Eingabeformate gleich, einschließlich der am häufigsten verwendeten Formate "1/1/1970" und "1/1/1970 00:00:00 AM". Alle folgenden Formate (und andere) werden in allen Browsern als lokale Zeitangabe behandelt und vor dem Speichern in UTC konvertiert. Dadurch sind sie Cross-Browser-kompatibel. Die Ausgabe dieses Codes ist in allen Browsern meiner Zeitzone gleich.
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"));
Auf der Ausgabeseite übersetzen alle Browser Zeitzonen auf dieselbe Weise, behandeln jedoch die Zeichenfolgenformate unterschiedlich. Hier sind die toString
-Funktionen und was sie ausgeben. Beachten Sie, dass die Funktionen toUTCString
und toISOString
um 5:00 Uhr auf meinem Computer ausgegeben werden.
Konvertiert von UTC in Ortszeit vor dem Drucken
- toString
- toDateString
- toTimeString
- toLocaleString
- toLocaleDateString
- toLocaleTimeString
Gibt die gespeicherte UTC-Zeit direkt aus
- toUTCString
- toISOString
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
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 Zeichenketten. Die Verwendung dieses Formats ist für mich nur dann von Vorteil, wenn Datumsangaben als Zeichenfolgen sortiert werden müssen. Das ISO-Format ist wie gewohnt sortierbar, 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 Pseudo-Transformation:
"12/4/2013" -> toUCT -> [storage] -> toLocal -> print "12/4/2013"
Ich hoffe diese Antwort war hilfreich.
Es gibt eine Methode für den Wahnsinn. Wenn ein Browser ein Datum als ISO-8601 interpretieren kann, ist dies in der Regel der Fall. "2005-07-08" fällt in dieses Lager und wird daher als UTC analysiert. "8. Juli 2005" kann nicht und daher wird es in der Ortszeit analysiert.
See JavaScript und Termine, was für ein Durcheinander! für mehr.
Eine andere Lösung besteht darin, ein assoziatives Array mit Datumsformat zu erstellen und die Daten anschließend neu zu formatieren.
Diese Methode ist nützlich für Datumsangaben, die unusual formatiert sind.
Ein Beispiel:
mydate='01.02.12 10:20:43':
myformat='dd/mm/yy HH:MM:ss';
dtsplit=mydate.split(/[\/ .:]/);
dfsplit=myformat.split(/[\/ .:]/);
// creates assoc array for date
df = new Array();
for(dc=0;dc<6;dc++) {
df[dfsplit[dc]]=dtsplit[dc];
}
// uses assc array for standard mysql format
dstring[r] = '20'+df['yy']+'-'+df['mm']+'-'+df['dd'];
dstring[r] += ' '+df['HH']+':'+df['MM']+':'+df['ss'];
Gemäß http://blog.dygraphs.com/2012/03/javascript-and-dates-what-mess.html löst das Format "yyyy/mm/dd" die üblichen Probleme. .__ Er sagt: "Halten Sie sich immer an" JJJJ/MM/TT "für Ihre Datumszeichenfolgen. Es wird universell unterstützt und ist eindeutig. Bei diesem Format sind alle Zeiten lokal." Ich habe Tests gesetzt: http://jsfiddle.net/jlanus/ND2Qg/432/ Dieses Format: + vermeidet die Unstimmigkeit der Tages- und Monatsbestellungen durch Verwendung der ym d-Reihenfolge und einer vierstelligen Jahreszahl + vermeidet, dass das UTC-Problem mit dem lokalen Format nicht mit dem ISO-Format übereinstimmt, indem Schrägstriche verwendet werden + danvk, der dygraphs , sagt, dass dieses Format in allen Browsern gut ist.
Verwenden Sie moment.js , um Daten zu analysieren:
var caseOne = moment("Jul 8, 2005", "MMM D, YYYY", true).toDate();
var caseTwo = moment("2005-07-08", "YYYY-MM-DD", true).toDate();
Das dritte Argument bestimmt das strikte Parsing (verfügbar ab 2.3.0). Andernfalls kann moment.js falsche Ergebnisse liefern.
Während CMS korrekt ist dass das Übergeben von Zeichenfolgen in die Parser-Methode im Allgemeinen unsicher ist, schlägt die neue ECMA-262 5th Edition (auch ES5) -Spezifikation in Abschnitt 15.9.4.2 vor, dass Date.parse()
eigentlich ISO-formatierte Daten behandeln sollte . Die alte Spezifikation machte keinen solchen Anspruch. Natürlich bieten alte Browser und einige aktuelle Browser diese ES5-Funktionalität nicht an.
Dein zweites Beispiel ist nicht falsch. Dies ist das in UTC angegebene Datum, wie in Date.prototype.toISOString()
angegeben, jedoch in Ihrer lokalen Zeitzone dargestellt.
Diese leichte Datums-Parsing-Bibliothek sollte alle ähnlichen Probleme lösen. Ich mag die Bibliothek, weil sie einfach zu erweitern ist. Es ist auch möglich, es zu machen (nicht sehr geradeaus, aber nicht so schwer).
Parsing-Beispiel:
var caseOne = Date.parseDate("Jul 8, 2005", "M d, Y");
var caseTwo = Date.parseDate("2005-07-08", "Y-m-d");
Und zurück zu string formatieren (Sie werden feststellen, dass beide Fälle genau das gleiche Ergebnis liefern):
console.log( caseOne.dateFormat("M d, Y") );
console.log( caseTwo.dateFormat("M d, Y") );
console.log( caseOne.dateFormat("Y-m-d") );
console.log( caseTwo.dateFormat("Y-m-d") );
Beide sind korrekt, werden jedoch als Datumsangaben mit zwei unterschiedlichen Zeitzonen interpretiert. Sie verglichen also Äpfel und Orangen:
// local dates
new Date("Jul 8, 2005").toISOString() // "2005-07-08T07:00:00.000Z"
new Date("2005-07-08T00:00-07:00").toISOString() // "2005-07-08T07:00:00.000Z"
// UTC dates
new Date("Jul 8, 2005 UTC").toISOString() // "2005-07-08T00:00:00.000Z"
new Date("2005-07-08").toISOString() // "2005-07-08T00:00:00.000Z"
Ich habe den Aufruf Date.parse()
entfernt, da er automatisch für ein String-Argument verwendet wird. Ich habe auch die Daten im ISO8601-Format verglichen, damit Sie die Daten zwischen Ihren lokalen Daten und den UTC-Daten visuell vergleichen können. Die Zeiten liegen im Abstand von 7 Stunden. Dies ist der Zeitunterschied, weshalb bei Ihren Tests zwei unterschiedliche Daten angezeigt wurden.
Die andere Möglichkeit, dieselben lokalen/UTC-Daten zu erstellen, wäre:
new Date(2005, 7-1, 8) // "2005-07-08T07:00:00.000Z"
new Date(Date.UTC(2005, 7-1, 8)) // "2005-07-08T00:00:00.000Z"
Ich empfehle jedoch weiterhin Moment.js , was einfach und dennoch mächtig ist:
// parse string
moment("2005-07-08").format() // "2005-07-08T00:00:00+02:00"
moment.utc("2005-07-08").format() // "2005-07-08T00:00:00Z"
// year, month, day, etc.
moment([2005, 7-1, 8]).format() // "2005-07-08T00:00:00+02:00"
moment.utc([2005, 7-1, 8]).format() // "2005-07-08T00:00:00Z"
Hier ist ein kurzes, flexibles Snippet, um eine datetime-Zeichenfolge browserübergreifend zu konvertieren, wie von @ drankin2112 detailliert beschrieben.
var inputTimestamp = "2014-04-29 13:00:15"; //example
var partsTimestamp = inputTimestamp.split(/[ \/:-]/g);
if(partsTimestamp.length < 6) {
partsTimestamp = partsTimestamp.concat(['00', '00', '00'].slice(0, 6 - partsTimestamp.length));
}
//if your string-format is something like '7/02/2014'...
//use: var tstring = partsTimestamp.slice(0, 3).reverse().join('-');
var tstring = partsTimestamp.slice(0, 3).join('-');
tstring += 'T' + partsTimestamp.slice(3).join(':') + 'Z'; //configure as needed
var timestamp = Date.parse(tstring);
Ihr Browser sollte das gleiche Zeitstempelergebnis wie Date.parse
enthalten:
(new Date(tstring)).getTime()
Die akzeptierte Antwort von CMS ist richtig, ich habe gerade einige Funktionen hinzugefügt:
// parse a date time that can contains spaces, dashes, slashes, colons
function parseDate(input) {
// trimes and remove multiple spaces and split by expected characters
var parts = input.trim().replace(/ +(?= )/g,'').split(/[\s-\/:]/)
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2] || 1, parts[3] || 0, parts[4] || 0, parts[5] || 0); // Note: months are 0-based
}