moment.js - UTC fornisce una data sbagliata


94

Perché moment.js UTC mostra sempre la data sbagliata. Ad esempio dalla console per sviluppatori di Chrome:

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

Entrambi torneranno "2013-07-17" perché tornerà 17 ° anziché 18 ° , che è stato approvato.

Ma se uso momentjs senza l'utc:

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

Torno indietro "2013-07-18", che è quello che mi aspetto anche quando utilizzo moment.js UTC.

Questo significa che non possiamo ottenere la data corretta quando si usa moment.js UTC?


4
Non credo che sia necessario toString()dopo format()(restituisce già una stringa).
alex

Risposte:


159

Per impostazione predefinita, MomentJS analizza l'ora locale. Se viene fornita solo una stringa di data (senza ora), l'ora predefinita è mezzanotte.

Nel tuo codice, crei una data locale e poi la converti nel fuso orario UTC (infatti, fa passare l'istanza del momento a modalità UTC ), quindi quando viene formattata, viene spostata (a seconda dell'ora locale) in avanti o indietro.

Se il fuso orario locale è UTC + N (N è un numero positivo) e analizzi una stringa di sola data, otterrai la data precedente.

Ecco alcuni esempi per illustrarlo (il mio fuso orario locale è UTC + 3 durante l'ora legale):

>>> 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)"

Se vuoi che la stringa data-ora venga interpretata come UTC, dovresti essere esplicito al riguardo:

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

oppure, come menziona Matt Johnson nella sua risposta, puoi ( e probabilmente dovresti ) analizzarlo come una data UTC in primo luogo utilizzando moment.utc()e includere la stringa di formato come secondo argomento per evitare ambiguità.

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

Per invertire la rotta e convertire una data UTC in una data locale, puoi utilizzare il local()metodo, come segue:

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

Grazie molto. Quindi, fondamentalmente, dovrei sempre passare nel tempo quando uso UTC o passare in UTC come nel tuo secondo approccio.
brg

O quello o attenersi al fuso orario locale. Se invii gli orari dal server, puoi esprimerli come timestamp Unix (X) o come stringhe in un fuso orario specifico. Perché utilizzare UTC invece del fuso orario locale dell'utente, comunque (eccetto per lo scopo di inviare dati normalizzati al server)?
MasterAM

1
Tieni presente che new Date('07-18-2013 UTC')non funzionerà in IE8, se ti interessa.
Dzmitry Lazerka

2
Ho lottato con questo per così tanto tempo. Dovrebbero davvero spiegarlo bene sul loro sito, poiché presumo che questo sia il caso d'uso più comune di moment.js. Grazie mille! Mi hai davvero salvato la pelle!
WebWanderer

questo codice funziona per me: [code] moment (strDate, 'DD / MM / YYYY h: mm A'). utc (strDate) .format ("YYYY-MM-DD HH: mm") [/ code]
Omar Isaid

36

Entrambi Datee momentanalizzeranno la stringa di input nel fuso orario locale del browser per impostazione predefinita. Tuttavia a Datevolte è incoerente con questo aspetto. Se la stringa è specificatamente YYYY-MM-DD, utilizza trattini , o se lo è YYYY-MM-DD HH:mm:ss, la interpreterà come ora locale . A differenza Date, momentsarà sempre coerente su come analizza.

Il modo corretto per analizzare un momento di input come UTC nel formato fornito sarebbe il seguente:

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

Fare riferimento a questa documentazione .

Se vuoi formattarlo in modo diverso per l'output, dovresti farlo:

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

Non è necessario chiamare toStringesplicitamente.

Notare che è molto importante fornire il formato di input. Senza di essa, un appuntamento come01-04-2013 potrebbe essere elaborata come 4 gennaio o 1 aprile, a seconda delle impostazioni della cultura del browser.


Solo per motivi di apprendimento, nella console: moment.utc ('2013-07-18 0:00 +0100', 'YYYY-MM-DD HH: mm') mi dà "2013-07-18 0:00 +0100 " Ma ciò che mostra jsfiddle quando viene eseguito è diverso, ovvero: Thu Jul 25 2013 01:00:00 GMT + 0100 Nota l' 01 : 00:00 . Grazie.
brg

L'output di un file raw momentsulla console non è molto utile. Probabilmente stai guardando una delle sue proprietà interne. Dovresti formattarlo prima di controllare i risultati. Ad esempio moment.utc().format()o moment().format().
Matt Johnson-Pint

Sia la data che l'ora analizzeranno la stringa di input nel fuso orario locale del browser per impostazione predefinita. Sono su EDT in questo momento. new Date('2010-12-12')mi dà Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}in FF 38.0.5. Giusto per contestualizzare cosa significa esattamente "nell'ora locale" - in questo caso, sembra significare, " Datepresumerà che una stringa senza fuso orario sia in UTC e analizzerà l'ora locale". d.getUTCDate()= 12e d.getDate()=11
ruffin

1
Sì, ci sono alcune eccezioni. ES5 (la maggior parte dei browser attuali) interpreterà le date con trattini come UTC, ma quasi tutto il resto viene interpretato come ora locale. ES6 sta modificando questo comportamento per interpretare la stessa stringa dell'ora locale. Ho aggiornato la risposta.
Matt Johnson-Pint

Ah, sì, mi sono imbattuto in questo a MDN dicendo esattamente questo ( '2012-12-12'è UTC b / c è in un formato ISO, ma 'December 12, 2012'e persino '2012/12/12'sono analizzati con un fuso orario locale in ES5), ma mi hai battuto. Così grandi che ES6 li rende tutti locali [disse sarcastico]. Le date sono un dolore, (c) Avvento delle date
ruffin
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.