Fusos Horários em TypeScript: Como Não Enlouquecer com Datas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que o tempo é uma dor de cabeça para todo desenvolvedor

\n\n

Você já pegou um bug onde um usuário de Vladivostok vê a data de amanhã, embora no calendário seja hoje? Ou quando um servidor em AWS us-east-1 envia um horário que seu cliente em Kaliningrado interpreta como 3 horas da manhã? Bem-vindo ao mundo dos fusos horários em TypeScript.

\n\n

O problema é que o JavaScript (e o TypeScript como sua extensão) foi originalmente projetado para navegadores. O objeto nativo Date é, essencialmente, um carimbo de data/hora mascarado em UTC. Ele não sabe trabalhar com fusos horários da maneira que precisamos. E se você está escrevendo um aplicativo sério em TypeScript — seja um painel de administração em React, um backend em Node.js ou um aplicativo móvel em React Native — não conseguirá evitar um trabalho adequado com timezones.

\n\n

Neste artigo, mostrarei como domar o tempo. Vamos entender os conceitos básicos, aprender a usar bibliotecas modernas e evitar as armadilhas típicas. Vamos lá!

\n\n

O que você precisa saber sobre fusos horários antes de escrever código

\n\n

Antes de mergulhar no TypeScript, vamos esclarecer as coisas. Existem dois tipos de tempo no mundo: o absoluto (UTC) e o local (o que o usuário vê).

\n\n
    \n
  • UTC (Tempo Universal Coordenado) — é o padrão. Servidores, bancos de dados e APIs devem armazenar o tempo em UTC. Esta é uma regra de ferro.
  • \n
  • Banco de Dados de Fusos Horários IANA — é um dicionário de fusos horários como Europe/Moscow, Asia/Vladivostok. São essas strings, e não abreviações como MSK ou PST, que devem ser usadas no código.
  • \n
  • Offset (deslocamento) — é a diferença em relação ao UTC, por exemplo +03:00. Mas lembre-se: o deslocamento pode mudar devido ao horário de verão (DST). Portanto, armazenar o offset em vez da zona IANA é uma má ideia.
  • \n
\n\n
\n

Regra de ouro: armazenamos em UTC, convertemos no cliente, usamos strings IANA para identificar zonas.

\n
\n\n

Por que o Date nativo não é suficiente: dor e sofrimento

\n\n

Vamos encarar a verdade: new Date() em TypeScript é como um canivete suíço com a lâmina quebrada. Ele só sabe armazenar um carimbo de data/hora e exibi-lo no fuso local do navegador ou servidor. Tente fazer algo mais complexo:

\n\n
// Exemplo ruim: tentando trabalhar com fusos usando meios nativos\nconst date = new Date('2024-03-10T12:00:00');\nconsole.log(date.toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' }));\n// Exibirá: "10/03/2024, 09:00:00" — mas é apenas uma string, não um objeto!\n\n// E se precisar obter um Date em outro fuso?\n// Ops... o JS nativo não sabe criar um Date vinculado a um fuso.\n
\n\n

O problema é que Date sempre armazena o tempo em UTC. Todos os métodos como getHours() apenas convertem o UTC para o horário local do navegador. Você não pode obter um objeto Date que "pense" que está em Nova York.

\n\n

É por isso que usamos bibliotecas. No ecossistema TypeScript, existem dois principais candidatos: Luxon e date-fns-tz.

\n\n

Luxon: artilharia pesada para trabalhar com datas

\n\n

Luxon é uma biblioteca moderna do criador do Moment.js (que já está obsoleto). Ela foi escrita do zero, usa o nativo Intl.DateTimeFormat e é perfeitamente tipada para TypeScript.

\n\n

Instalação do Luxon

\n\n
npm install luxon\nnpm install --save-dev @types/luxon\n
\n\n

Criando uma data em um fuso horário específico

\n\n
import { DateTime } from 'luxon';\n\n// Criando uma data no fuso America/Sao_Paulo\nconst saoPauloTime = DateTime.fromObject(\n  { year: 2024, month: 3, day: 10, hour: 12 },\n  { zone: 'America/Sao_Paulo' }\n);\nconsole.log(saoPauloTime.toISO());\n// Saída: "2024-03-10T12:00:00.000-03:00"\n\n// Convertendo para outro fuso\nconst nyTime = saoPauloTime.setZone('America/New_York');\nconsole.log(nyTime.toISO());\n// Saída: "2024-03-10T11:00:00.00                

Blogs

Book Recommendations