Trabalhando com fusos horários e timestamps Unix sem bugs
Datas e horas causam um número desproporcional de bugs, porque o que parece óbvio para um humano é genuinamente complicado para um computador: fusos horários mudam, relógios pulam uma hora duas vezes por ano e 'hoje' depende de onde você está. Este guia explica as ideias centrais e dá um punhado de regras que evitam a maioria dos erros ao lidar com datas.
Armazene o tempo como um instante absoluto
A regra mais importante: armazene e transmita momentos como um instante absoluto e independente de fuso — um timestamp Unix (segundos ou milissegundos desde 1 de janeiro de 1970 UTC) ou uma string ISO 8601 em UTC (terminada em Z). Um instante é o mesmo em toda a Terra; só a sua representação humana muda.
Converta para um fuso local apenas na borda, quando exibe o valor a uma pessoa. Mantenha o interior do seu sistema em UTC. A maioria dos bugs de data dolorosos vem de armazenar uma hora 'local' sem registrar a qual fuso ela pertencia, deixando o valor ambíguo para sempre.
UTC, deslocamentos e fusos não são a mesma coisa
UTC é o relógio de referência global. Um deslocamento como +09:00 é uma diferença fixa em relação ao UTC num momento. Um fuso horário, como America/New_York, é um conjunto nomeado de regras que descreve qual deslocamento se aplica em cada ponto da história — inclusive quando ele muda.
A distinção importa porque os deslocamentos mudam dentro de um único fuso. Nova York é -05:00 no inverno e -04:00 no verão. Armazenar só um deslocamento perde a regra, então você não consegue calcular corretamente uma hora local futura. É por isso que agendar 'todo dia às 9h horário de Nova York' precisa do nome do fuso, não de um deslocamento fixo.
O horário de verão quebra suposições ingênuas
Duas vezes por ano, os fusos que adotam o horário de verão pulam. Na primavera uma hora é omitida, então uma hora local como 02:30 simplesmente não existe naquele dia; no outono uma hora se repete, então 01:30 acontece duas vezes e é ambígua. Código que assume que todo dia tem 24 horas, ou que uma dada hora local sempre existe, mais cedo ou mais tarde produzirá resultados errados ou travará.
Trabalhar em UTC evita isso por completo, porque o UTC não tem horário de verão. Você só enfrenta as lacunas e sobreposições ao converter para hora local para exibição ou ao interpretar a entrada humana — que é exatamente onde uma biblioteca de datas testada deve fazer o trabalho, em vez de aritmética feita à mão.
Segundos, milissegundos e o ano 2038
Timestamps Unix vêm em duas unidades comuns e misturá-las é um bug frequente: a maioria das ferramentas e APIs Unix usa segundos, enquanto o Date do JavaScript trabalha em milissegundos. Um valor errado por um fator de 1000 geralmente significa que as unidades foram confundidas — um timestamp de repente no ano 56000, ou de volta em 1970.
Há também um limite de tamanho: um tempo Unix armazenado num inteiro de 32 bits com sinal transborda em 19 de janeiro de 2038. Sistemas modernos usam valores de 64 bits, o que elimina o problema para fins práticos, mas vale saber por que sistemas antigos lidam mal com datas muito distantes.
Regras que evitam a maioria dos bugs
Nada disso exige conhecimento profundo no dia a dia — alguns hábitos cobrem a grande maioria dos casos.
- Armazene e troque instantes em UTC (timestamp Unix ou ISO 8601 com Z); converta para local só para exibir.
- Mantenha o nome de fuso IANA (ex.: Europe/Paris) quando uma hora local futura importa; um deslocamento sozinho não basta.
- Nunca faça contas de calendário somando números fixos de segundos para 'um dia' ou 'um mês' — use uma biblioteca de datas que conheça o horário de verão e a duração dos meses.
- Seja explícito sobre segundos vs milissegundos em cada fronteira, e rotule qual você quer dizer.