moment.js - UTC gibt falsches Datum an

93

Warum zeigt moment.js UTC immer das falsche Datum an? Zum Beispiel von der Entwicklerkonsole von Chrome:

moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Beide werden "2013-07-17" zurückgeben, warum wird der 17. statt der 18. zurückgegeben , der übergeben wurde.

Aber wenn ich momentjs ohne utc benutze:

moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Ich bekomme "2013-07-18" zurück , was ich auch erwarte, wenn ich moment.js UTC benutze.

Bedeutet dies, dass wir bei Verwendung von moment.js UTC nicht das richtige Datum erhalten können?

brg
quelle
4
Ich glaube nicht , Sie müssen toString()nach format()(es bereits einen String zurückgibt).
Alex

Antworten:

156

Standardmäßig analysiert MomentJS die Ortszeit. Wenn nur eine Datumszeichenfolge (ohne Uhrzeit) angegeben wird, wird standardmäßig Mitternacht verwendet.

In Ihrem Code erstellen Sie ein lokales Datum und konvertieren es dann in die UTC-Zeitzone (tatsächlich wechselt die Momentinstanz in den UTC-Modus ). Wenn sie formatiert wird, wird sie (abhängig von Ihrer Ortszeit) vorwärts oder vorwärts verschoben rückwärts.

Wenn die lokale Zeitzone UTC + N ist (N ist eine positive Zahl) und Sie eine Nur-Datum-Zeichenfolge analysieren, erhalten Sie das vorherige Datum.

Hier einige Beispiele zur Veranschaulichung (mein lokaler Zeitversatz ist UTC + 3 während der Sommerzeit):

>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"

Wenn Sie möchten, dass die Datums- / Uhrzeitzeichenfolge als UTC interpretiert wird, sollten Sie dies explizit angeben:

>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

oder, wie Matt Johnson in seiner Antwort erwähnt, können ( und sollten ) Sie es zunächst als UTC-Datum analysieren moment.utc()und die Formatzeichenfolge als zweites Argument einschließen, um Mehrdeutigkeiten zu vermeiden.

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

Um umgekehrt ein UTC-Datum in ein lokales Datum umzuwandeln, können Sie die folgende local()Methode verwenden:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"
MasterAM
quelle
Danke vielmals. Grundsätzlich sollte ich bei der Verwendung von UTC immer rechtzeitig vergehen oder UTC wie bei Ihrem zweiten Ansatz übergeben.
Brg
Entweder das oder die lokale Zeitzone einhalten. Wenn Sie Zeiten vom Server senden, können Sie diese als Unix-Zeitstempel (X) oder als Zeichenfolgen in einer bestimmten Zeitzone ausdrücken. Warum sollte UTC überhaupt anstelle der lokalen Zeitzone des Benutzers verwendet werden (außer zum Normalisieren normalisierter Daten an den Server)?
MasterAM
1
new Date('07-18-2013 UTC')Beachten Sie, dass dies in IE8 nicht funktioniert, wenn Sie sich darum kümmern.
Dzmitry Lazerka
2
Ich habe so lange damit zu kämpfen. Sie sollten dies wirklich gut auf ihrer Website erklären lassen, da ich davon ausgehe, dass dies der häufigste Anwendungsfall von moment.js ist. Ich danke dir sehr! Du hast meine Haut wirklich gerettet!
WebWanderer
Dieser Code funktioniert für mich: [Code] Moment (strDate, 'TT / MM / JJJJ h: mm A'). utc (strDate) .format ("JJJJ-MM-TT HH: mm") [/ code]
Omar Isaid
36

Beide Dateund momentanalysieren standardmäßig die Eingabezeichenfolge in der lokalen Zeitzone des Browsers. Dies Datesteht jedoch manchmal im Widerspruch dazu. Wenn die Zeichenfolge speziell YYYY-MM-DDmit Bindestrichen versehen ist oder wenn dies der Fall ist YYYY-MM-DD HH:mm:ss, wird sie als Ortszeit interpretiert . Im Gegensatz zu Date, momentwird immer konsistent darüber , wie es analysiert.

Die richtige Methode zum Analysieren eines Eingabemoments als UTC in dem von Ihnen angegebenen Format lautet wie folgt:

moment.utc('07-18-2013', 'MM-DD-YYYY')

Siehe diese Dokumentation .

Wenn Sie es dann für die Ausgabe anders formatieren möchten, gehen Sie folgendermaßen vor:

moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')

Sie müssen nicht toStringexplizit anrufen .

Beachten Sie, dass es sehr wichtig ist, das Eingabeformat anzugeben. Ohne dieses Datum wird ein Datum wie das 01-04-2013möglicherweise entweder als 4. Januar oder als 1. April verarbeitet, abhängig von den Kultureinstellungen des Browsers.

Matt Johnson-Pint
quelle
Nur zum Lernen, in der Konsole: moment.utc ('2013-07-18 0:00 +0100', 'JJJJ-MM-TT HH: mm') gibt mir "2013-07-18 0:00 +0100 " Aber was auf jsfiddle beim Ausführen nicht angezeigt wird, ist anders: Do 25.07.2013 01:00:00 GMT + 0100 Beachten Sie die 01:00:00 . Vielen Dank.
Brg
Die Ausgabe eines Raw momentauf der Konsole ist nicht sehr nützlich. Sie sehen sich wahrscheinlich eine der internen Eigenschaften an. Sie sollten es formatieren, bevor Sie die Ergebnisse überprüfen. Zum Beispiel moment.utc().format()oder moment().format().
Matt Johnson-Pint
Sowohl Datum als auch Moment analysieren standardmäßig die Eingabezeichenfolge in der lokalen Zeitzone des Browsers. Ich bin gerade bei EDT. new Date('2010-12-12')gibt mir Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}in FF 38.0.5. Nur um zu kontextualisieren, was "in der Ortszeit" genau bedeutet - in diesem Fall scheint es zu bedeuten, " Datewird angenommen, dass sich eine zonenlose Zeitzeichenfolge in UTC befindet und nach der Ortszeit analysiert wird." d.getUTCDate()= 12und d.getDate()=11
Ruffin
1
Ja, es gibt einige Ausnahmen. ES5 (die meisten aktuellen Browser) interpretiert Datumsangaben mit Bindestrichen als UTC, aber fast alles andere wird als Ortszeit interpretiert. ES6 ändert dieses Verhalten, um dieselbe Zeichenfolge wie die Ortszeit zu interpretieren. Ich habe die Antwort aktualisiert.
Matt Johnson-Pint
Ha, yep, bin gerade bei MDN darauf gestoßen und habe genau das gesagt ( '2012-12-12'ist UTC b / c, es hat ein ISO-Format, wird aber 'December 12, 2012'sogar '2012/12/12'mit einer lokalen Zeitzone in ES5 analysiert), aber Sie haben mich geschlagen. So großartig, dass ES6 sie alle lokal macht [sagte er sarkastisch]. Termine sind ein Schmerz, (c) Advent of Dates
Ruffin