Formatar data em um fuso horário específico

177

Estou usando o Moment.js para analisar e formatar datas no meu aplicativo da web. Como parte de um objeto JSON, meu servidor back-end envia datas como um número de milissegundos da época UTC (deslocamento do Unix).

A análise de datas em um fuso horário específico é fácil - basta anexar o identificador de fuso horário RFC 822 ao final da sequência antes de analisar:

// 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>

Mas como formato uma data em um fuso horário específico ?

Desejo resultados consistentes, independentemente do horário atual do navegador, mas não quero exibir datas no UTC.

quietmint
fonte
2
O momento ainda não suporta isso, mas eles estão trabalhando nisso. github.com/timrwood/moment/pull/671 #
Ben Ben
5
Isso deve funcionar. Se você passar por um momento uma sequência de tempo que inclua o deslocamento desejado, ele deverá reter esse deslocamento e exibir a hora local conforme determinado, em vez de se ajustar automaticamente à hora local do navegador. Se eu quisesse que ele se ajustasse à hora local do navegador, daria uma hora UTC em vez de explicitamente dar um deslocamento para usar. Quero dizer ... eu dou um deslocamento explícito, por que ele está basicamente comendo e fazendo sua própria conversão para o deslocamento do navegador? Design terrível.
Triynko
As compensações @Triynko estão sujeitas ao horário de verão, portanto, nem sempre funciona como esperado.
pinkpanther
1
Algo relacionado a isso, quero imprimir a hora em um formato específico, por exemplo, 15 de março de 2018, mas não consigo encontrar a string de formato para fazer isso. O genérico DD MMM, YYYYnão funciona, quando eu uso moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). Alguém pode me apontar na documentação onde posso encontrar todas as chaves para formatar o tempo ao usar esta API.
PRmdk
@PramodKumar O que há de errado? Isso dá "15 Feb, 2018". Você queria usar a string de formato DD MMMM, YYYYpara obter "15 February, 2018"?
quietmint

Respostas:

248

Como apontado na resposta de Manto , .utcOffset()é o método preferido a partir do Momento 2.9.0. Esta função usa o deslocamento real do UTC, não o deslocamento reverso (por exemplo, -240 para Nova York durante o horário de verão). Seqüências de caracteres deslocadas como "+0400" funcionam da mesma maneira 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')

O mais antigo .zone()como setter foi descontinuado no Moment.js 2.9.0. Ele aceitou uma sequência contendo um identificador de fuso horário (por exemplo, "-0400" ou "-04: 00" por -4 horas) ou um número que representa minutos atrás do UTC (por exemplo, 240 para Nova York durante o horário de verão).

// 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 trabalhar com fusos horários nomeados em vez de deslocamentos numéricos, inclua fuso horário do momento e use .tz():

// 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
fonte
Eu estava tendo problemas com isso por meio de um erro "TypeError: Object 240 has no method 'format'". Percebi que a zona só está disponível como setter na versão 2.1.0 e posterior do Moment.js (e eu estava em uma versão mais antiga). Obrigado!
Melinda Weathers #
5
@ebi Já usa o fuso horário do navegador por padrão. Para acessar o deslocamento do fuso horário do navegador, use .zone()como um getter, que retorna minutos do UTC (por exemplo, retorna 300 para Nova York durante o horário padrão).
quietmint
1
@EricCope Não, não exatamente. No entanto, você pode usar .tz("America/Phoenix")se incluir momentjs.com/timezone . Atualizei a resposta com um exemplo.
quietmint
1
Observe que o uso do deslocamento não funcionará conforme o esperado se o fuso horário tiver compensações diferentes devido ao horário de verão.
pinkpanther
1
O .utcOffset () gerencia automaticamente o horário de verão? como quando defino o UTC +1 CET no inverno, ele aposta no UTC +2 CEST durante o horário de verão? Porque isso o torna utilizável ou não!
haemse
61

Usar fuso horário

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

Antes de poder acessar um fuso horário específico, você precisará carregá-lo dessa forma (ou usar métodos alternativos descritos aqui )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Philip Nuzhnyy
fonte
Não acho que o momento tz estivesse disponível quando a pergunta foi feita, mas acho que esse pode ser o caminho a seguir. Atualmente, estou trabalhando em um problema semelhante com todos os carimbos de data e hora armazenados como UTC no MySQL, mas para ser visualizado em uma zona específica dependente da configuração do usuário e não do fuso horário do cliente.
nickdnk
47

Algumas respostas já mencionam que o fuso horário é o caminho a seguir com o fuso horário nomeado. Eu só quero esclarecer algo sobre essa biblioteca que foi bastante confuso para mim. Há uma diferença entre essas duas instruções:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

Supondo que um fuso horário não esteja especificado na data passada em:

O primeiro código incorpora a data e assume que o fuso horário é o informado. O segundo codifica a data, assume o fuso horário do navegador e altera a hora e o fuso horário de acordo com o fuso horário informado.

Exemplo:

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"

Meu fuso horário é +5 de utc. Portanto, no primeiro caso, ele não muda e define a data e a hora para o utc fuso horário.

No segundo caso, ele assume que a data passada está em -5, depois a transforma em UTC, e é por isso que indica a data "2018-07-18T00: 00: 00Z"

NOTA: O parâmetro format é realmente importante. Se o momento omitido puder retornar à classe Date, o que pode comportamentos imprevisíveis


Supondo que o fuso horário esteja especificado na data passada em:

Nesse caso, ambos se comportam igualmente


Embora agora eu entenda por que funciona dessa maneira, achei que esse era um recurso bastante confuso e que vale a pena explicar.

Nicola Pedretti
fonte
1
momento (...) .z não é uma função
K - A toxicidade no SO está crescendo.
5
Você instalou o fuso horário?
Nicola Pedretti
existe uma maneira de recuperar o momento analisado e convertido sem formatação? Por exemplo, se eu quiser formatar maneiras diferentes sem analisar tudo de novo.
jEremyB
Obrigado por esclarecer isso. Ocorreu um problema ao definir um fuso horário diferente do fuso horário do navegador do usuário e esse foi o problema exato.
Robin Schaaf
20

.zone () foi descontinuado e você deve usar utcOffset:

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

Eu estava tendo o mesmo problema com o Moment.js. Instalei o fuso horário, mas o problema não foi resolvido. Então, fiz exatamente o que aqui está exposto, defini o fuso horário e funciona como um encanto:

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

Muito obrigado!

facundofarias
fonte
16
Você não deve usar o new Date()construtor. O momento fornece tudo o que você precisa para analisar datas. Consulte Analisando documentos.
quietmint
Sim, mas se eu não fizer isso, eu estou recebendo um aviso de momento, que está obsoleta de algo assim
facundofarias
7
O aviso significa que o Moment está internamente voltando exatamente ao que você está fazendo (usando new Date()internamente), mas isso é inconsistente nos navegadores . Em vez disso, você deve usar o formato esperado como o segundo argumento. Exemplo: moment("12-25-1995", "MM-DD-YYYY").
quietmint
4

Acabei de chegar a esse ponto e, como eu tinha o mesmo problema, publicaria os resultados que obtive

ao analisar, você pode atualizar o deslocamento (ou seja, estou analisando os dados (1.1.2014) e quero apenas a data, 1º de janeiro de 2014. No GMT + 1, recebo 31.12.2013. Portanto, compenso o valor primeiro.

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

Bem, veio a calhar para eu apoiar nos fusos horários

B

Bard Rotzer
fonte
-7

Você pode tentar isso,

Aqui você pode obter a data com base no fuso horário do cliente (navegador).

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

O regex basicamente fornece o valor do deslocamento.

Felicidades!!

K.Karthik
fonte
Normalmente, o momento dá tudo o que você precisa. Você nunca precisa corresponder a nada personalizado.
Mahesh Samudra