Os carimbos de data/hora Unix são um dos formatos de dados mais importantes na programação — eles aparecem em registros de banco de dados, respostas de API, arquivos de log, metadados de sistema de arquivos, tokens de autenticação e inúmeros outros lugares. O formato é elegantemente simples: um único número inteiro representando segundos (ou milissegundos, microssegundos ou nanossegundos) desde 1º de janeiro de 1970. No entanto, trabalhar corretamente com carimbos de data e hora é surpreendentemente complicado devido ao tratamento de fuso horário, incompatibilidades de precisão entre sistemas e casos extremos de horário de verão. As seções abaixo explicam o que é o horário Unix e por que ele existe, como lidar corretamente com os fusos horários durante a conversão e os bugs comuns que pegam os desenvolvedores mesmo após anos de experiência.
O que é o tempo Unix e por que ele existe
O horário Unix, também chamado de horário Epoch ou horário POSIX, é o número de segundos decorridos desde 1º de janeiro de 1970 00:00:00 UTC — um ponto de referência chamado época Unix. Os valores negativos representam datas anteriores a essa época, os valores positivos representam datas posteriores. O formato se originou no início da década de 1970, quando os sistemas Unix precisavam de uma maneira compacta e independente de fuso horário para armazenar carimbos de data e hora nos metadados do sistema de arquivos e nos registros de log. Um único número inteiro assinado de 32 bits poderia representar datas de 1901 a 2038, o que parecia suficiente em tempo de design, mas cria o famoso problema do ano 2038 quando esse intervalo expira. Os sistemas modernos usam números inteiros de 64 bits, adiando a validade para o ano 292 bilhões. A elegância do horário Unix é que ele não tem fuso horário, horário de verão, segundos bissextos (oficialmente - a maioria das implementações simplesmente mancha os raros segundos bissextos) e nenhuma complexidade de calendário. É um contador crescente monotonicamente que identifica inequivocamente um momento específico. Fusos horários, datas do calendário e formatos legíveis são todos colocados na parte superior no horário de exibição. Isso torna o horário Unix o formato preferido para comparações (`if (tokenExpiresAt < now)`), classificação e armazenamento de carimbos de data e hora em bancos de dados em sistemas distribuídos que abrangem fusos horários. Formatos legíveis por humanos, como `2024-04-21 11:58:41`, são derivados do valor Unix armazenado somente quando exibidos para um usuário.
Tratamento de fuso horário – a parte sutil
Um carimbo de data/hora Unix em si não tem fuso horário — ele representa um momento específico em tempo absoluto. Ao converter para um formato legível, você escolhe um fuso horário para exibição, e o mesmo carimbo de data/hora produz horários locais diferentes em fusos diferentes. Por exemplo, 1713711521 segundos após a época são 15:58:41 UTC, mas esse mesmo momento é 11:58:41 EDT (América/Nova_Iorque, UTC-4), 08:58:41 PDT (América/Los_Angeles, UTC-7), 00:58:41 JST do dia seguinte (Ásia/Tóquio, UTC+9) e incontáveis outros horários locais em todo o mundo. Para acertar isso na prática, são necessários nomes de fuso horário da IANA, como `América/Nova_York`, em vez de compensações fixas, como `UTC-05:00`, porque os nomes da IANA codificam o histórico completo do horário de verão. Dizer "16h EST em 15 de julho de 2024" é na verdade ambíguo porque o horário do leste observa o horário de verão e as datas de julho estão em EDT (UTC-4), não em EST (UTC-5). Os fusos horários da IANA resolvem essa ambigüidade automaticamente - a API Intl do navegador e as bibliotecas do lado do servidor, como pytz, moment-timezone e ZoneId do Java, usam o banco de dados da IANA e lidam com transições históricas de horário de verão corretamente. Este conversor usa o Intl.DateTimeFormat integrado do navegador com suporte total ao fuso horário da IANA, o que significa que ele produz horários locais corretos para qualquer fuso válido, incluindo datas históricas que remontam a 1970 ou anteriores.
Os bugs comuns que pegam até mesmo desenvolvedores experientes
Um punhado de bugs de carimbo de data e hora aparecem com tanta frequência que vale a pena internalizá-los como uma lista de verificação. Primeiro, confusão entre segundos e milissegundos: o objeto Date do JavaScript funciona em milissegundos, enquanto time.time() do Python funciona em segundos, e misturá-los acidentalmente multiplica ou divide suas datas por 1000. Verifique a magnitude: números de 10 dígitos são segundos, 13 dígitos são milissegundos, 16 dígitos são microssegundos. Em segundo lugar, suposição de fuso horário na análise: a string "2024-04-21 11:58:41" não tem fuso horário e analisadores diferentes assumem suposições diferentes como padrão. O construtor Date do JavaScript trata-o como hora local; O datetime.fromisoformat do Python o trata como ingênuo (sem fuso horário). Sempre anexe um fuso horário explícito a strings ambíguas antes de analisar. Terceiro, casos extremos do horário de verão nas transições de primavera e outono: 2h30 no dia de primavera não existe na maioria dos fusos horários dos EUA (o relógio salta de 1h59 para 3h) e 1h30 no dia alternativo existe duas vezes. A aritmética de datas que adiciona ou subtrai horas através de um limite de horário de verão pode produzir resultados surpreendentes, a menos que você use bibliotecas compatíveis com IANA. Quarto, o “agora” varia entre os servidores: os relógios dos servidores variam em milissegundos ou segundos, portanto, os tokens gerados em um servidor e validados em outro precisam de uma janela de tolerância. Quinto, segundos bissextos: raramente relevantes na prática porque a maioria dos sistemas os mancha, mas são críticos para aplicações científicas ou financeiras precisas. Este conversor evita a maioria deles usando as APIs internacionais bem testadas do navegador, mas os conceitos subjacentes ainda são importantes ao escrever código que consome valores convertidos.