moment.js - UTC da una fecha incorrecta

94

¿Por qué moment.js UTC siempre muestra la fecha incorrecta? Por ejemplo, desde la consola de desarrollo de Chrome:

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

Ambos regresarán "2013-07-17" por qué regresa el 17 en lugar del 18 , que se pasó.

Pero si uso momentjs sin utc:

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

Vuelvo "2013-07-18", que es lo que también espero cuando uso moment.js UTC.

¿Significa esto que no podemos obtener la fecha correcta cuando usamos moment.js UTC?

brg
fuente
4
No creo que necesites toString()después format()(ya devuelve una cadena).
alex

Respuestas:

159

De forma predeterminada, MomentJS analiza en la hora local. Si solo se proporciona una cadena de fecha (sin hora), la hora predeterminada es medianoche.

En su código, crea una fecha local y luego la convierte a la zona horaria UTC (de hecho, hace que la instancia de momento cambie al modo UTC ), por lo que cuando se formatea, se desplaza (según su hora local) hacia adelante o hacia adelante hacia atrás.

Si la zona horaria local es UTC + N (N es un número positivo) y analiza una cadena de solo fecha, obtendrá la fecha anterior.

Aquí hay algunos ejemplos para ilustrarlo (mi compensación de hora local es UTC + 3 durante DST):

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

Si desea que la cadena de fecha y hora se interprete como UTC, debe ser explícito al respecto:

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

o, como Matt Johnson menciona en su respuesta, puede ( y probablemente debería ) analizarlo como una fecha UTC en primer lugar utilizando moment.utc()e incluir la cadena de formato como un segundo argumento para evitar ambigüedad.

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

Para ir al revés y convertir una fecha UTC en una fecha local, puede usar el local()método de la siguiente manera:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"
MasterAM
fuente
Muchas gracias. Entonces, básicamente, siempre debería pasar el tiempo cuando uso UTC o pasar UTC como en su segundo enfoque.
brg
O eso o ceñirse a la zona horaria local. Si envía horas desde el servidor, puede expresarlas como marca de tiempo Unix (X) o como cadenas en una zona horaria específica. ¿Por qué usar UTC en lugar de la zona horaria local del usuario, de todos modos (excepto con el propósito de enviar datos normalizados al servidor)?
MasterAM
1
Tenga en cuenta que new Date('07-18-2013 UTC')no funcionará en IE8, si le importa.
Dzmitry Lazerka
2
He estado luchando con esto durante tanto tiempo. Realmente deberían tener esto bien explicado en su sitio, ya que supongo que este es el caso de uso más común de moment.js. Muchas gracias! ¡Realmente salvaste mi pellejo!
WebWanderer
este código funciona para mí: [código] momento (strDate, 'DD / MM / AAAA h: mm A'). utc (strDate) .format ("AAAA-MM-DD HH: mm") [/ código]
Omar Dije el
36

Ambos Datey momentanalizarán la cadena de entrada en la zona horaria local del navegador de forma predeterminada. Sin embargo, a Dateveces es incompatible con este aspecto. Si la cadena es específicamente YYYY-MM-DD, usando guiones , o si lo es YYYY-MM-DD HH:mm:ss, la interpretará como hora local . A diferencia Date, momentsiempre será coherente sobre cómo analiza.

La forma correcta de analizar un momento de entrada como UTC en el formato que proporcionó sería así:

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

Consulte esta documentación .

Si desea luego formatearlo de manera diferente para la salida, debe hacer esto:

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

No es necesario llamar toStringexplícitamente.

Tenga en cuenta que es muy importante proporcionar el formato de entrada. Sin él, una fecha como 01-04-2013podría procesarse como 4 de enero o 1 de abril, según la configuración cultural del navegador.

Matt Johnson-Pinta
fuente
Solo por aprender, en la consola: moment.utc ('2013-07-18 0:00 +0100', 'AAAA-MM-DD HH: mm') me da "2013-07-18 0:00 +0100 " Pero lo que se muestra en jsfiddle cuando se ejecuta es diferente, es decir: jueves 25 de julio de 2013 01:00:00 GMT + 0100 Tenga en cuenta las 01:00:00 . Gracias.
brg
La salida de un raw momenten la consola no es muy útil. Probablemente esté mirando una de sus propiedades internas. Debe formatearlo antes de verificar los resultados. Por ejemplo moment.utc().format()o moment().format().
Matt Johnson-Pint
Tanto la fecha como el momento analizarán la cadena de entrada en la zona horaria local del navegador de forma predeterminada. Estoy en EDT ahora mismo. new Date('2010-12-12')me da Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}en FF 38.0.5. Solo para contextualizar lo que significa exactamente "en la hora local"; en este caso, parece significar " Dateasumirá que una cadena sin zona horaria está en UTC y se analizará en la hora local". d.getUTCDate()= 12y d.getDate()=11
ruffin
1
Sí, existen algunas excepciones. ES5 (la mayoría de los navegadores actuales) interpretará las fechas con guiones como UTC, pero casi todo lo demás se interpreta como hora local. ES6 está cambiando este comportamiento para interpretar la misma cadena como hora local. Actualicé la respuesta.
Matt Johnson-Pint
Ja, sí, me encontré con esto en MDN diciendo exactamente eso ( '2012-12-12'es UTC b / c, está en formato ISO, pero 'December 12, 2012'e incluso '2012/12/12'se analizan con una zona horaria local en ES5), pero me has adelantado. Tan genial que ES6 los hace a todos locales [dijo sarcásticamente]. Las fechas son un dolor, (c) Adviento de las fechas
ruffin