Formato de fecha en una zona horaria específica

177

Estoy usando Moment.js para analizar y formatear fechas en mi aplicación web. Como parte de un objeto JSON, mi servidor de fondo envía fechas como una cantidad de milisegundos desde la época UTC (desplazamiento de Unix).

Analizar fechas en una zona horaria específica es fácil: solo agregue el identificador de zona horaria RFC 822 al final de la cadena antes de analizar:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Pero, ¿cómo formateo una fecha en una zona horaria específica ?

Quiero resultados consistentes independientemente de la hora actual del navegador, pero no quiero mostrar las fechas en UTC.

quietmint
fuente
2
Moment aún no admite esto, pero están trabajando en ello. github.com/timrwood/moment/pull/671
Ben
55
Esto debería funcionar. Si pasa una cadena de tiempo que incluye el desplazamiento deseado, entonces debe conservar ese desplazamiento y mostrar la hora local como se indica, en lugar de ajustar automáticamente la hora local del navegador. Si quisiera que se ajustara a la hora local del navegador, entonces le daría una hora UTC en lugar de darle explícitamente una compensación para usar. Quiero decir ... le doy un desplazamiento explícito, ¿por qué básicamente se lo está comiendo y haciendo su propia conversión al desplazamiento del navegador? Terrible diseño.
Triynko
Las compensaciones de @Triynko están sujetas al horario de verano, por lo que no siempre funciona como se esperaba.
pinkpanther
1
Algo relacionado con esto, quiero imprimir el tiempo en un formato específico, por ejemplo, 15 de marzo de 2018, pero no puedo encontrar la cadena de formato para hacerlo. El genérico DD MMM, YYYYno funciona, cuando lo uso como moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). ¿Alguien puede señalarme en la documentación donde puedo encontrar todas las claves para formatear el tiempo cuando uso esta API?
pRmdk
@PramodKumar ¿Qué pasa? Eso da "15 Feb, 2018". ¿Querías usar el formato de cadena DD MMMM, YYYYpara obtener "15 February, 2018"?
quietmint

Respuestas:

248

Como se señaló en la respuesta de Manto , .utcOffset()es el método preferido a partir del momento 2.9.0. Esta función utiliza el desplazamiento real desde UTC, no el desplazamiento inverso (por ejemplo, -240 para Nueva York durante el horario de verano). Las cadenas de desplazamiento como "+0400" funcionan igual que antes:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

El más antiguo .zone()como setter quedó en desuso en Moment.js 2.9.0. Aceptó una cadena que contiene un identificador de zona horaria (por ejemplo, "-0400" o "-04: 00" durante -4 horas) o un número que representa minutos detrás de UTC (por ejemplo, 240 para Nueva York durante el horario de verano).

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

Para trabajar con zonas horarias con nombre en lugar de desplazamientos numéricos, incluya Moment Timezone y use .tz()en su lugar:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
quietmint
fuente
Estaba teniendo problemas con esto a través de un error "TypeError: Object 240 no tiene ningún método 'formato'". Me di cuenta de que la zona solo está disponible como setter en la versión 2.1.0 y posteriores de Moment.js (y estaba en una versión anterior). ¡Gracias!
Melinda Weathers
55
@ebi Ya usa la zona horaria del navegador por defecto. Para acceder al desplazamiento de zona horaria del navegador, úselo .zone()como un captador, que devuelve minutos desde UTC (por ejemplo, devuelve 300 para Nueva York durante la hora estándar)
quietmint
1
@EricCope No, no del todo. Usted puede utilizar .tz("America/Phoenix")si se incluyen momentjs.com/timezone así, sin embargo. He actualizado la respuesta con un ejemplo.
quietmint
1
Tenga en cuenta que el uso de la compensación no funcionará como se esperaba si la zona horaria tiene diferentes compensaciones debido al horario de verano.
pinkpanther
1
¿.UtcOffset () administrará automáticamente los horarios de verano? como cuando configuro UTC +1 CET en invierno, ¿apostará UTC +2 CEST durante el horario de verano? ¡Porque esto lo hace utilizable o no!
haemse
61

Usar zona horaria

moment(date).tz('Europe/Berlin').format(format)

Antes de poder acceder a una zona horaria en particular, deberá cargarla así (o usar los métodos alternativos descritos aquí )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Philip Nuzhnyy
fuente
No creo que haya un momento disponible cuando se hizo la pregunta, pero sí creo que este podría ser el camino a seguir. Actualmente estoy trabajando en un problema similar con todas las marcas de tiempo almacenadas como UTC en MySQL, pero para verlas en una zona específica que depende de la configuración del usuario y no de la zona horaria del cliente.
nickdnk
47

Un par de respuestas ya mencionan que la zona horaria es el camino a seguir con la zona horaria con nombre. Solo quiero aclarar algo sobre esta biblioteca que fue bastante confuso para mí. Hay una diferencia entre estas dos declaraciones:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

Suponiendo que no se especifica una zona horaria en la fecha pasada:

El primer código toma la fecha y asume que la zona horaria es la que se pasó. El segundo tomará la fecha, asumirá la zona horaria del navegador y luego cambiará la hora y la zona horaria de acuerdo con la zona horaria pasada.

Ejemplo:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

Mi zona horaria es +5 de utc. Entonces, en el primer caso, no cambia y establece la fecha y la hora para tener la zona horaria utc.

En el segundo caso, se supone que la fecha aprobada está en -5, luego se convierte en UTC, y es por eso que escupe la fecha "2018-07-18T00: 00: 00Z"

NOTA: El parámetro de formato es realmente importante. Si se omite el momento, puede recurrir a la clase Fecha que puede comportamientos impredecibles


Asumiendo que la zona horaria se especifica en la fecha pasada:

En este caso, ambos se comportan igual


Aunque ahora entiendo por qué funciona de esa manera, pensé que era una característica bastante confusa y que valía la pena explicar.

Nicola Pedretti
fuente
1
momento (...). tz no es una función
K - La toxicidad en SO está creciendo.
55
¿Instalaste moment-timezone?
Nicola Pedretti
¿Hay alguna manera de recuperar el momento analizado y convertido sin formatear? Por ejemplo, si quiero formatear diferentes formas sin analizarlo de nuevo.
jEremyB
Gracias por aclarar esto: he tenido problemas al configurar una zona horaria diferente a la zona horaria del navegador del usuario, y este fue el problema exacto.
Robin Schaaf
20

.zone () ha quedado en desuso, y en su lugar debería usar utcOffset:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
Manto
fuente
8

Estaba teniendo el mismo problema con Moment.js. He instalado momentzone, pero el problema no se resolvió. Luego, hice lo que aquí está expuesto, configuré la zona horaria y funciona de maravilla:

moment(new Date({your_date})).zone("+08:00")

¡Muchas gracias!

facundofarias
fuente
16
No deberías usar el new Date()constructor. Moment proporciona todo lo que necesitas para analizar las fechas. Ver Análisis de documentos.
quietmint
Sí, pero si no hago eso, recibo una advertencia de Moment, que está en desuso por algo así
facundofarias
77
La advertencia significa que Moment está volviendo internamente a exactamente lo que está haciendo (usando new Date()internamente), pero esto es inconsistente en todos los navegadores . En su lugar, debe usar proporcionar el formato esperado como segundo argumento. Ejemplo: moment("12-25-1995", "MM-DD-YYYY").
quietmint
4

Acabo de acreoss esto, y como tenía el mismo problema, simplemente publicaría los resultados que se me ocurrieron.

al analizar, puede actualizar el desplazamiento (es decir, estoy analizando un dato (1.1.2014) y solo quiero la fecha, 1 de enero de 2014. En GMT + 1 obtendría 31.12.2013. Así que compensé el valor primero.

moment(moment.utc('1.1.2014').format());

Bueno, fue útil para mí apoyar en todas las zonas horarias

si

Bard Rotzer
fuente
-7

Puedes probar esto,

Aquí puede obtener la fecha en función de la zona horaria del cliente (navegador).

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

La expresión regular básicamente te da el valor de compensación.

¡¡Salud!!

K.Karthik
fuente
Por lo general, momento te da todo lo que necesitas. Nunca es necesario que coincida con nada personalizado.
Mahesh Samudra