Aguarde...

30 de julho de 2019

Manipulando o fuso horário em JavaScript

Manipulando o fuso horário em JavaScript

Recentemente, trabalhei em uma tarefa de adicionar um recurso de fuso horário ao TOAST UI Calendar , a biblioteca de calendários JavaScript gerenciada por minha equipe. Eu sabia muito bem que o suporte ao fuso horário em JavaScript é muito ruim, mas esperava que abstrair objetos de dados existentes resolvesse facilmente muitos problemas.

No entanto, minha esperança era falsa e achei muito difícil lidar com o fuso horário em JavaScript à medida que progredia mais. A implementação de recursos de fuso horário além da simples formatação de tempo e do cálculo de dados de tempo com operações complexas (por exemplo, calendário) era uma tarefa realmente difícil. Por essa razão, tive uma experiência valiosa e emocionante de resolver um problema que causa mais problemas.

O objetivo deste artigo é discutir os problemas e soluções relacionados à implementação de recursos de fuso horário usando JavaScript. Enquanto escrevia este longo artigo, de repente percebi que a raiz do meu problema estava na minha má compreensão do domínio do fuso horário. A partir disso, discutirei primeiro a definição e os padrões relacionados ao fuso horário em detalhes e, em seguida, falarei sobre JavaScript.

O que é o fuso horário?

Um fuso horário é uma região que segue um horário local uniforme que é legalmente declarado pelo país. É comum que muitos países tenham seu fuso horário exclusivo, e alguns países grandes, como os EUA ou o Canadá, têm até vários fusos horários. Curiosamente, embora a China seja grande o suficiente para ter vários fusos horários, ela usa apenas um fuso horário. Isso às vezes resulta em uma situação tão embaraçosa, onde o sol nasce por volta das 10h na parte ocidental da China.

GMT, UTC e offset

GMT

A hora local coreana é normalmente GMT +09:00. GMT é uma abreviação de Greenwich Mean Time, que é a hora do Observatório Real em Greenwich, Reino Unido, localizada na longitude 0. O sistema GMT começou a se espalhar em 5 de fevereiro de 1925 e se tornou o padrão mundial até 1 de janeiro de 1972. .

UTC

Muitos consideram o GMT e o UTC a mesma coisa, e os dois são usados ​​de forma intercambiável em muitos casos, mas na verdade são diferentes. A UTC foi criada em 1972 para compensar o problema de desaceleração da rotação da Terra. Este sistema de tempo é baseado no tempo atômico internacional, que usa a freqüência atômica de césio para definir o padrão de tempo. Em outras palavras, o UTC é o sistema de substituição mais preciso do GMT. Embora a diferença de tempo real entre os dois seja pequena, a UTC é a escolha mais precisa para desenvolvedores de software.

Quando o sistema ainda estava em desenvolvimento, os anglofones queriam nomear o sistema CUT (Tempo Universal Coordenado) e os francófonos queriam chamá-lo de TUC (Temps Universal Coordonn). No entanto, nenhum dos dois lados ganhou a luta, então eles chegaram a um acordo de usar o UTC, já que continha todas as letras essenciais (C, T e U).

Offset

+09:00 em UTC+09:00 significa que a hora local está 9 horas adiantada do que a hora padrão UTC.Isso significa que são 21h na Coreia, quando são 12h em uma região UTC. A diferença de tempo entre o UTC tempo padrão e o horário local é chamado de “compensação”, que se expressa desta forma: +09:00-03:00, etc.

É comum que os países nomeiem seu fuso horário usando seus próprios nomes exclusivos. Por exemplo, o fuso horário da Coreia é chamado KST (Korea Standard Time) e tem um certo valor de deslocamento que é expresso como KST = UTC+09:00. No entanto, o +09:00deslocamento também é usado não apenas pela Coréia, mas também pelo Japão, Indonésia e muitos outros, o que significa que a relação entre compensações e nomes de fusos horários não é 1: 1, mas 1: N. A lista de países no +09:00deslocamento pode ser encontrada em UTC + 09: 00 .

Algumas compensações não são estritamente de hora em hora. Por exemplo, a Coreia do Norte usa +08:30como seu tempo padrão enquanto a Austrália usa +08:45ou +09:30 depende da região.

A lista inteira de deslocamentos UTC e seus nomes pode ser encontrada em Lista de deslocamentos do Tempo UTC .

Fuso horário! == offset?

Como mencionei anteriormente, usamos os nomes dos fusos horários (KST, JST) de forma intercambiável com o deslocamento sem distingui-los. Mas não é certo tratar o tempo e o deslocamento de uma determinada região da mesma forma pelas seguintes razões:

Horário de verão (DST)

Embora esse termo possa não ser familiar a alguns países, muitos países do mundo adotaram o horário de verão. “Horário de verão” é um termo usado principalmente no Reino Unido e outros países europeus. Internacionalmente, é normalmente chamado de horário de verão (DST). Isso significa avançar os relógios para uma hora à frente do horário padrão durante o horário de verão.

Por exemplo, a Califórnia nos EUA usa o PST (Horário Padrão do Pacífico) durante o inverno e usa o PDT (Horário de Verão do Pacífico UTC-07:00) durante o horário de verão. As regiões que usam os dois fusos horários são coletivamente chamadas de Horário do Pacífico (PT), e esse nome é adotado por muitas regiões dos EUA e do Canadá.

Então a próxima pergunta é exatamente quando o verão começa e termina. Na verdade, as datas de início e término do horário de verão são todas diferentes, variando de país para país. Por exemplo, nos EUA e no Canadá, o horário de verão costumava ser do primeiro domingo de abril às 02:00 até o último domingo de outubro às 12:00 AM até 2006, mas desde 2007 o DST foi iniciado no segundo domingo de Março às 02:00 até o primeiro domingo de novembro às 02:00. Na Europa, o horário de verão é aplicado uniformemente em todos os países, enquanto o horário de verão é aplicado progressivamente a cada fuso horário nos estados.

O fuso horário muda?

Como mencionei anteriormente, cada país tem seu próprio direito de determinar qual fuso horário usar, o que significa que seu fuso horário pode ser alterado devido a qualquer motivo político e / ou econômico. Por exemplo, nos estados, o período de DST foi alterado em 2007 porque o presidente George Bush assinou a política energética em 2005. Egito e Rússia costumavam usar o DST, mas deixaram de usá-lo desde 2011.

Em alguns casos, um país pode alterar não apenas seu horário de verão, mas também seu horário padrão. Por exemplo, Samoa costumava usar a UTC-10:00compensação, mas depois mudou para a UTC+14:00compensação para reduzir as perdas na negociação causadas pela diferença de fuso horário entre Samoa e Austrália e Nova Zelândia. Esta decisão fez com que o país perdesse o dia inteiro de 30 de dezembro de 2011 e o fizesse aos jornais de todo o mundo .

A Holanda costumava usar o +0:19:32.13offset, que é desnecessariamente preciso desde 1909, mas mudou para +00:20compensar em 1937, e depois mudou novamente para +01:00offset em 1940, aderindo a ele até agora.

Fuso Horário 1: Offset N

Para resumir, um fuso horário pode ter um ou mais deslocamentos. O deslocamento que um país utilizará como seu tempo padrão em um determinado momento pode variar devido a razões políticas e / ou econômicas.

Este não é um grande problema na vida cotidiana, mas é quando se tenta sistematizá-lo com base em regras. Vamos imaginar que você queira definir um horário padrão para o seu smartphone usando um deslocamento. Se você mora em uma região aplicada ao horário de verão, o horário do smartphone deve ser ajustado sempre que o horário de verão começar e terminar. Nesse caso, você precisaria de um conceito que reunisse o horário padrão e o horário de verão em um fuso horário (por exemplo, horário do Pacífico).

Mas isso não pode ser implementado com apenas algumas regras simples. Por exemplo, como os estados alteraram as datas que o horário de verão começa e termina em 2007, 31 de maio de 2006 deve usar PDT ( -07:00) como o tempo padrão enquanto 31 de março de 2007 deve usar PST ( -08:00) como o tempo padrão. Isso significa que, para se referir a um fuso horário específico, você deve conhecer todos os dados históricos dos fusos horários padrão ou o momento em que as regras de horário de verão foram alteradas.

Você não pode simplesmente dizer: “fuso horário de Nova York é PST ( -08:00).” Você deve ser mais específico, dizendo, por exemplo, “de Nova York atual fuso horário é PST.” No entanto, precisamos de uma expressão mais precisa para o bem da implementação do sistema. Esqueça a palavra “fuso horário”. Você precisa dizer: “Nova York está usando o PST como seu horário padrão”.

Então, o que devemos usar além de offset para designar o fuso horário de uma região específica? A resposta é o nome da região. Para ser mais específico, você deve agrupar regiões nas quais as alterações no horário de verão ou no fuso horário padrão foram aplicadas uniformementeem um fuso horário e consultá-las conforme apropriado. Você pode usar nomes como PT (Horário do Pacífico), mas esse termo só combina o horário padrão atual e seu horário de verão, não necessariamente todas as alterações históricas. Além disso, como o PT é usado atualmente apenas nos EUA e no Canadá, você precisa de padrões mais bem estabelecidos de organizações confiáveis ​​para usar o software universalmente.

Banco de dados de fusos horários da IANA

Para dizer a verdade, os fusos horários são mais um banco de dados do que uma coleção de regras, pois devem conter todas as alterações históricas relevantes. Existem vários bancos de dados padrão projetados para lidar com os problemas de fuso horário, e o mais usado é o Banco de Dados de Fuso Horário da IANA . Geralmente chamado de banco de dados tz (ou tzdata), o banco de dados do fuso horário da IANA contém os dados históricos do horário padrão local em todo o mundo e as alterações do horário de verão. Este banco de dados é organizado para conter todos os dados históricos atualmente verificáveis ​​para garantir a precisão do tempo desde a hora do Unix ( 1970.01/01 00:00:00). Embora também tenha dados antes de 1970, a precisão não é garantida.

A convenção de nomenclatura segue a regra Área / Localização. Área geralmente se refere ao nome de um continente ou um oceano (Ásia, América, Pacífico) enquanto a localização do nome das principais cidades, como Seul e Nova York, em vez do nome dos países (Isso ocorre porque a vida útil de um país é muito menor que a de uma cidade). Por exemplo, o fuso horário da Coreia é Asia/Seoule o do Japão é Asia/Tokyo. Embora os dois países compartilhem o mesmo UTC+09:00, ambos os países têm histórias diferentes em relação ao fuso horário. É por isso que os dois países são tratados usando fusos horários separados.

O banco de dados de fusos horários da IANA é gerenciado por várias comunidades de desenvolvedores e historiadores. Fatos históricos e políticas governamentais recém-descobertas são atualizados imediatamente para o banco de dados, tornando-se a fonte mais confiável. Além disso, muitos sistemas operacionais baseados em UNIX, incluindo Linux e MacOS, e linguagens de programação populares, incluindo Java e PHP, usam internamente esse banco de dados.

Observe que o Windows não está na lista de suporte acima. É porque o Windows usa seu próprio banco de dados chamado Microsoft Time Zone Database . No entanto, esse banco de dados não reflete com precisão as alterações históricas e é gerenciado somente pela Microsoft. Portanto, é menos preciso e confiável do que a IANA.

Banco de dados de fusos horários do JavaScript e da IANA

Como mencionei anteriormente, o recurso de fuso horário do JavaScript é bastante ruim. Como ele segue o fuso horário da região por padrão (para ser mais específico, o fuso horário selecionado no momento da instalação do SO), não há como alterá-lo para um novo fuso horário. Além disso, as especificações do banco de dados padrão não são claras, o que você observará se observar de perto a especificação do ES2015. Apenas algumas declarações vagas são declaradas em relação ao fuso horário local e à disponibilidade do horário de verão. Por exemplo, o horário de verão é definido da seguinte maneira: ECMAScript 2015 – Ajuste do horário de verão

Um algoritmo dependente da implementação usando as melhores informações disponíveis sobre fusos horários para determinar o ajuste do horário de verão DaylightSavingTA (t), medido em milissegundos. Espera-se que uma implementação do ECMAScript faça o possível para determinar o ajuste do horário de verão local.

Parece que é simplesmente dizer: “Ei, pessoal, experimentem e façam o possível para que funcione”. Isso também deixa um problema de compatibilidade entre os fornecedores de navegadores. Você pode pensar “Isso é desleixado!”, Mas então você vai notar outra linha logo abaixo:

OBSERVAÇÃO: é recomendável que as implementações usem as informações de fuso horário do banco de dados de fusos horários da IANA http://www.iana.org/time-zones/ .

Sim. As especificações da ECMA lançam a bola para você com esta simples recomendação para o banco de dados de fusos horários da IANA, e o JavaScript não possui um banco de dados padrão específico preparado para você. Como resultado, navegadores diferentes usam suas próprias operações de fuso horário para o cálculo de fuso horário e, com frequência, não são compatíveis entre si. Mais tarde, as especificações ECMA adicionaram uma opção para usar o fuso horário da IANA no ECMA-402 Intl.DateTimeFormatpara a API internacional. No entanto, essa opção ainda é muito menos confiável do que para outras linguagens de programação.

Fuso Horário no Ambiente Servidor-Cliente

Vamos supor um cenário simples em que o fuso horário deve ser considerado. Vamos dizer que vamos desenvolver um aplicativo de calendário simples que manipulará informações de tempo. Quando um usuário insere data e hora no campo na página de registro no ambiente do cliente, os dados são transferidos para o servidor e armazenados no banco de dados. Em seguida, o cliente recebe os dados de agendamento registrados do servidor para exibi-lo na tela.

Há algo a considerar aqui embora. E se alguns dos clientes acessando o servidor estiverem em fusos horários diferentes? Uma programação registrada para 10 de março de 2017 às 11:30 em Seul deve ser exibida em 10 de março de 2017 às 21:30 quando o horário é visto em Nova York. Para o servidor suportar clientes de vários fusos horários, o planejamento armazenado no servidor deve ter valores absolutos que não são afetados por fusos horários. Cada servidor tem uma maneira diferente de armazenar valores absolutos, e isso está fora do escopo deste artigo, já que é tudo diferente, dependendo do ambiente do servidor ou do banco de dados. No entanto, para que isso funcione, a data e a hora transferidas do cliente para o servidor devem ser valores baseados no mesmo deslocamento (geralmente UTC) ou valores que também incluem os dados de fuso horário do ambiente do cliente.

É uma prática comum que esse tipo de dado seja transferido na forma de horário Unix baseado em UTC ou ISO-8601 contendo as informações de offset. No exemplo acima, se as 09:00 de 10 de março de 2017 em Seul forem convertidas em horário Unix, será um tipo inteiro de valor 1489113000. Sob ISO-8601, será um tipo de cadeia de qual valor é 2017–03–10T11:30:00+09:00.

Se você estiver trabalhando com isso usando JavaScript em um ambiente de navegador, deverá converter o valor inserido conforme descrito acima e, em seguida, convertê-lo novamente para caber no fuso horário do usuário. Ambas as duas tarefas devem ser consideradas. No sentido de linguagem de programação, o primeiro é chamado de “análise” e o segundo, “formatação”. Agora vamos descobrir como eles são manipulados em JavaScript.

Mesmo quando você está trabalhando com JavaScript em um ambiente de servidor usando o Node.js, pode ser necessário analisar os dados recuperados do cliente, dependendo do caso. No entanto, como os servidores normalmente têm seu fuso horário sincronizado com o banco de dados e a tarefa de formatação geralmente é deixada para os clientes, você tem menos fatores a considerar do que em um ambiente de navegador. Neste artigo, minha explicação será baseada no ambiente do navegador.

Objeto de data em JavaScript

Em JavaScript, tarefas envolvendo data ou hora são tratadas usando um Dateobjeto. É um objeto nativo definido no ECMAScript, como Arrayou Function. que é principalmente implementado em código nativo, como C ++. Sua API é bem descrita em documentos MDN . É muito influenciado pela classe java.util.Date do Java . Como resultado, herda algumas características indesejáveis, como as características dos dados mutáveis ​​e monthcomeçando com 0.

Dateobjeto do JavaScript gerencia internamente os dados de tempo usando valores absolutos, como o tempo do Unix. No entanto, construtores e métodos como parse() função, getHour()setHour(), etc. são afetados pela zona do cliente hora local (o fuso horário do sistema operacional executando o navegador, para ser exato). Portanto, se você criar um Dateobjeto diretamente usando dados de entrada do usuário, os dados refletirão diretamente o fuso horário local do cliente.

Como mencionei anteriormente, o JavaScript não fornece nenhuma maneira arbitrária de alterar o fuso horário. Portanto, vou assumir uma situação aqui onde a configuração de fuso horário do navegador pode ser usada diretamente.

Criando objeto de data com entrada de usuário

Vamos voltar ao primeiro exemplo. Suponha que um usuário entrou às 11h30 de 11 de março de 2017 em um dispositivo que segue o fuso horário de Seul. Esses dados são armazenados em 5 inteiros de 2017, 2, 11, 11 e 30 – cada um representando o ano, mês, dia, hora e minuto, respectivamente. (Como o mês começa com 0, o valor deve ser 3–1 = 2.) Com um construtor, você pode criar facilmente um objeto Date usando os valores numéricos.

const d1 = new Date (2017, 2, 11, 11, 30); 
d1.toString (); // Sábado 11 Mar 2017 11:30:00 GMT + 0900 (KST)

Se você olhar o valor retornado por d1.toString(), saberá que o valor absoluto do objeto criado é 11:00, 11 de março de 2017 com base no deslocamento +09:00(KST).

Você também pode usar o construtor junto com dados de string. Se você usar um valor de string para o Dateobjeto, ele chama internamente Date.parse()e calcula o valor adequado. Esta função suporta as especificações RFC2888 e as especificações ISO-8601 . No entanto, conforme descrito no documento Date.parse () do MDN , o valor de retorno desse método varia de navegador para navegador e o formato do tipo de seqüência de caracteres pode afetar a previsão do valor exato. Assim, recomenda-se não usar este método.

Por exemplo, uma string como 2015–10–12 12:00:00retorna NaNno Safari e no Internet Explorer, enquanto a mesma string retorna o fuso horário local no Chrome e no Firefox. Em alguns casos, retorna o valor com base no padrão UTC.

Criando o objeto Date usando dados do servidor

Vamos supor agora que você receberá dados do servidor. Se os dados forem do valor numérico de tempo do Unix, você pode simplesmente usar o construtor para criar um Dateobjeto. Embora eu tenha ignorado a explicação anteriormente, quando um Dateconstrutor recebe um único valor como o único parâmetro, ele é reconhecido como um valor de tempo do Unix em milissegundos. (Cuidado: o JavaScript manipula o tempo do Unix em milissegundos. Isso significa que o segundo valor deve ser multiplicado por 1.000.) Se você vir o exemplo abaixo, o valor resultante será o mesmo do exemplo anterior.

const d1 = new Date (1489199400000); 
d1.toString (); // Sábado 11 Mar 2017 11:30:00 GMT + 0900 (KST)

Então, e se um tipo de string como ISO-8601 for usado no lugar do tempo Unix? Como expliquei no parágrafo anterior, o Date.parse()método não é confiável e é melhor não ser usado. No entanto, como o ECMAScript 5 ou versões posteriores especificam o suporte do ISO-8601, você pode usar strings no formato especificado pela ISO-8601 para o Dateconstrutor no Internet Explorer 9.0 ou superior que suporte ECMAScript 5, se for usado com cuidado. 
Se você estiver usando um navegador que não seja a versão mais recente, mantenha a Zcarta no final. Sem ele, seu navegador antigo às vezes o interpreta com base em seu horário local em vez de UTC. Abaixo está um exemplo de executá-lo no Internet Explorer 10.

const d1 = new Date ('2017-03-11T11: 30: 00'); 
const d2 = new Date ('2017-03-11T11: 30: 00Z');
d1.toString (); // "Sábado Mar 11 11:30:00 UTC + 0900 2017"
d2.toString (); // "Sábado Mar 11 20:30:00 UTC + 0900 2017"

De acordo com as especificações, os valores resultantes de ambos os casos devem ser os mesmos. No entanto, como você pode ver, os valores resultantes são diferentes como d1.toString() d2.toString(). No navegador mais recente, esses dois valores serão os mesmos. Para evitar esse tipo de problema de versão, você deve sempre adicionar Zno final de uma string, se não houver dados de fuso horário.

Criando dados para serem transferidos para o servidor

Agora use o Dateobjeto criado anteriormente e você pode adicionar ou subtrair livremente o tempo com base nos fusos horários locais. Mas não se esqueça de converter seus dados de volta ao formato anterior no final do processamento antes de transferi-los de volta ao servidor.

Se é hora do Unix, você pode simplesmente usar o getTime()método para fazer isso. (Observe o uso de milissegundos).

const d1 = new Date (2017, 2, 11, 11, 30); 
d1.getTime (); // 1489199400000

E quanto às strings do formato ISO-8601? Como explicado anteriormente, o Internet Explorer 9.0 ou superior que suporta ECMAScript 5 ou superior suporta o formato ISO-8601. Você pode criar strings do formato ISO-8601 usando o método toISOString()ou toJSON(). ( toJSON()pode ser usado para chamadas recursivas com JSON.stringify()ou outros.) Os dois métodos produzem os mesmos resultados, exceto no caso em que manipula dados inválidos.

const d1 = new Date (2017, 2, 11, 11, 30); 
d1.toISOString (); // "2017-03-11T02: 30: 00.000Z"
d1.toJSON (); // "2017-03-11T02: 30: 00.000Z"

const d2 = new Date ('Olá');
d2.toISOString (); // Erro: Data inválida
d2.toJSON (); // nulo

Você também pode usar o método toGMTString()ou toUTCString()para criar seqüências de caracteres no UTC. À medida que retornam uma string que satisfaz o padrão RFC-1123 , você pode aproveitar isso conforme necessário.

Objetos de data incluem toString()toLocaleString()e seus métodos de extensão. No entanto, como esses são usados ​​principalmente para retornar uma string com base no fuso horário local e retornam valores variados, dependendo do navegador e do sistema operacional usados, eles não são realmente úteis.

Alterando o fuso horário local

Você pode ver agora que o JavaScript fornece um pouco de suporte para o fuso horário. E se você quiser alterar a configuração de fuso horário local em seu aplicativo sem seguir a configuração de fuso horário do seu sistema operacional? Ou se você precisar exibir uma variedade de fusos horários ao mesmo tempo em um único aplicativo? Como eu disse várias vezes, o JavaScript não permite a alteração manual do fuso horário local. A única solução para isso é adicionar ou remover o valor do deslocamento da data, desde que você já saiba o valor do deslocamento do fuso horário. Não fique frustrado ainda embora. Vamos ver se há alguma solução para contornar isso.

Vamos continuar com o exemplo anterior, assumindo que o fuso horário do navegador está definido como Seul. O usuário entra 11:30, 11 de março de 2017 com base na hora de Seul e quer vê-lo na hora local de Nova York. O servidor transfere os dados de tempo Unix em milissegundos e notifica que o valor de compensação de Nova York é -05:00. Então você pode converter os dados se você souber apenas o deslocamento do fuso horário local.

Nesse cenário, você pode usar o getTimeZoneOffset()método. Esse método é a única API em JavaScript que pode ser usada para obter as informações do fuso horário local. Ele retorna o valor de deslocamento do fuso horário atual em minutos.

const seoul = new Date (1489199400000); 
seoul.getTimeZoneOffset (); // -540

O valor de retorno -540significa que o fuso horário está 540 minutos à frente do destino. Esteja avisado que o sinal de menos na frente do valor é oposto ao sinal de adição de Seul ( +09:00). Eu não sei porque, mas é assim que é exibido. Se calcularmos o deslocamento de Nova York usando esse método, obteremos 60 * 5 = 300. Converta a diferença 840em milissegundos e crie um novo objeto Date. Então você pode usar os getXXmétodos desse objeto para converter o valor em um formato de sua escolha. Vamos criar uma função de formatador simples para comparar os resultados.

function formatDate (date) { 
return date.getFullYear () + '/' +
(data.getMonth () + 1) + '/' +
date.getDate () + '' +
date.getHours () + ':' +
date.getMinutes ();
}

const seoul = new Date (1489199400000);
const ny = new Date (1489199400000 - (840 * 60 * 1000));

formatDate (seoul); // 2017/3/11 11:30
formatDate (ny); // 2017/3/10 21:30

formatDate()mostra a data e hora corretas de acordo com a diferença de fuso horário entre Seul e Nova York. Parece que encontramos uma solução simples. Então podemos convertê-lo para o fuso horário local se soubermos o deslocamento da região? Infelizmente, a resposta é “Não”. Lembre-se do que eu disse antes? Esses dados de fuso horário são um tipo de banco de dados que contém o histórico de todas as alterações de deslocamento? Para obter o valor de fuso horário correto, você deve saber o valor do deslocamento no momento da data (não da data atual).

Problema da conversão do fuso horário local

Se você continuar trabalhando com o exemplo acima um pouco mais, logo enfrentará um problema. O usuário deseja verificar a hora em Nova York e alterar a data de 11 a 15. Se você usar o setDate()método do objeto Date, poderá alterar a data deixando outros valores inalterados.

ny.setDate (15); 
formatDate (ny); // 2017/3/15 21:30

Parece bastante simples, mas há uma armadilha escondida aqui. O que você faria se tivesse que transferir esses dados de volta para o servidor? Como os dados foram alterados, você não pode usar métodos como getTime()ou getISOString(). Portanto, você deve reverter a conversão antes de enviá-la de volta ao servidor.

tempo de const = ny.getTime () + (840 * 60 * 1000); // 1489631400000

Alguns de vocês podem se perguntar por que adicionei usando os dados convertidos quando preciso convertê-los de qualquer maneira antes de retornar. Parece que posso processá-lo sem conversão e criar temporariamente um objeto Date convertido somente quando estou formatando. No entanto, não é o que parece. Se você alterar a data de um Dateobjeto com base na hora de Seul de 11 a 15, 4 dias serão adicionados ( 24 * 4 * 60 * 60 * 1000). No entanto, na hora local de Nova York, como a data foi alterada de 10 para 15, foram adicionados 5 dias ( 24* 5 * 60 * 60 * 1000). Isso significa que você deve calcular as datas com base no deslocamento local para obter o resultado preciso.

O problema não pára por aqui. Há outro problema em que você não deseja obter valor desejado simplesmente adicionando ou subtraindo compensações. Desde 12 de março é a data de início do horário de verão em Nova York, a compensação de 15 de março de 2017 -04:00não deve ser -05:00. Então, quando você reverter a conversão, você deve adicionar 780 minutos, o que é 60 minutos a menos do que antes.

tempo de const = ny.getTime () + (780 * 60 * 1000); // 1489627800000

Pelo contrário, se o fuso horário local do usuário for Nova York e quiser saber a hora em Seul, o DST será aplicado desnecessariamente, causando outro problema.

Simplificando, você não pode usar o deslocamento obtido sozinho para executar as operações precisas com base no fuso horário de sua escolha. Se você relembrar o que discutimos na parte anterior deste documento, você facilmente saberia que ainda há um buraco nessa conversão se você souber as regras do horário de verão. Para obter o valor exato, você precisa de um banco de dados que contenha todo o histórico de alterações de deslocamento, como o Banco de dados do fuso horário da IANA .

Para resolver esse problema, é necessário armazenar todo o banco de dados de fuso horário e sempre que os dados de data ou hora forem recuperados do Dateobjeto, localizar a data e o deslocamento correspondente e, em seguida, converter o valor usando o processo acima. Em teoria, isso é possível. Mas, na realidade, isso exige muito esforço e testar a integridade dos dados convertidos também será difícil. Mas não fique desapontado ainda. Até agora, discutimos alguns problemas de JavaScript e como resolvê-los. Agora estamos prontos para usar uma biblioteca bem construída.

Momento Fuso Horário

Momento é uma biblioteca JavaScript bem estabelecida que é quase o padrão para a data de processamento. Fornecendo uma variedade de APIs de data e formatação, é reconhecida por muitos usuários recentemente como estável e confiável. E há o Moment Timezone , um módulo de extensão, que resolve todos os problemas discutidos acima. Esse módulo de extensão contém os dados do banco de dados de fusos horários da IANA para calcular com precisão os deslocamentos e fornece uma variedade de APIs que podem ser usadas para alterar e formatar o fuso horário.

Neste artigo, não discutirei como usar a biblioteca ou a estrutura da biblioteca em detalhes. Mostrarei apenas como é simples resolver os problemas que discuti anteriormente. Se alguém estiver interessado, consulte o documento Moment Timezone’s .

Vamos resolver o problema mostrado na imagem usando o Moment Timezone.

const seoul = momento (1489199400000) .tz ('Ásia / Seul'); 
const ny = momento (1489199400000) .tz ('America / New_York');

seoul.format (); // 2017-03-11T11: 30: 00 + 09: 00
ny.format (); // 2017-03-10T21: 30: 00-05: 00

seoul.date (15) .format (); // 2017-03-15T11: 30: 00 + 09: 00
ny.date (15) .format (); // 2017-03-15T21: 30: 00-04: 00

Se você vir o resultado, o deslocamento seoulpermanece o mesmo enquanto o deslocamento de nyfoi alterado de -05:00para -04:00. E se você usar a format()função, você pode obter uma seqüência de caracteres no formato ISO-8601 que aplicou com precisão o deslocamento. Você verá como é simples comparado ao que expliquei anteriormente.

Postado em BlogTags:
Escreva um comentário