Entendendo timestamps Unix: Um guia para desenvolvedores
O que são timestamps Unix, como funcionam, segundos intercalares, o problema de 2038 e conversão prática.
Por que os desenvolvedores devem entender timestamps Unix
Um timestamp Unix é um inteiro representando o número de segundos decorridos desde 00:00:00 UTC de 1 de janeiro de 1970 (a época Unix). Eles são a língua franca do tempo na computação: bancos de dados os indexam, APIs os retornam, sistemas de arquivos os armazenam, e protocolos como NTP e HTTP os usam. Todo desenvolvedor eventualmente tem que converter entre timestamps Unix e datas legíveis por humanos — e depurar os problemas que surgem quando diferentes sistemas representam o tempo de maneira diferente.
Este guia cobre o que são timestamps Unix, como funcionam em diferentes linguagens, as complicações de fuso horário e segundo intercalar, e o problema do 2038 que se aproxima.
Como os timestamps Unix funcionam
Um timestamp Unix é apenas uma contagem inteira de segundos. Não há fuso horário, não há horário de verão, não há aritmética de calendário. Adicionar 86.400 a um timestamp sempre avança a data exatamente um dia em UTC.
``` 0 = 1970-01-01 00:00:00 UTC (a época) 1,000 = 1970-01-01 00:16:40 UTC 1,000,000 = 1970-01-12 13:46:40 UTC 1,000,000,000 = 2001-09-09 01:46:40 UTC (o "bilênio") 1,500,000,000 = 2017-07-14 02:40:00 UTC 2,000,000,000 = 2033-05-18 03:33:20 UTC 2,147,483,647 = 2038-01-19 03:14:07 UTC (máx. 32 bits com sinal) ```
O maior valor representável depende do tipo de inteiro:
- 32 bits com sinal: 2.147.483.647 (2^31 − 1) → 2038-01-19 03:14:07 UTC
- 32 bits sem sinal: 4.294.967.295 (2^32 − 1) → 2106-02-07 06:28:15 UTC
- 64 bits com sinal: 9.223.372.036.854.775.807 → ano 292.277.026.596
Por isso o problema de 2038 existe: qualquer timestamp com sinal de 32 bits transborda em 2038-01-19. Timestamps de 64 bits evitam o problema por centenas de bilhões de anos.
Tempo Unix vs UTC: o problema do segundo intercalar
Estritamente, o tempo Unix ignora os segundos intercalares. Ele conta cada segundo como se houvesse exatamente 86.400 por dia, mesmo quando as autoridades internacionais de tempo adicionam um segundo intercalar ao UTC. Depois que 27 segundos intercalares foram inseridos (a partir de 2024), o tempo Unix agora está cerca de 27 segundos à frente do UTC "verdadeiro".
Na prática, isso raramente importa. TAI (Tempo Atômico Internacional) mantém segundos perfeitos, e UTC fica dentro de 0,9 segundo de UT1 (tempo de rotação da Terra) adicionando segundos intercalares. O tempo Unix simplesmente usa a contagem de segundos de TAI menos um deslocamento fixo.
Se você precisa de tempo atômico estrito, use TAI diretamente. Para todo o resto, a pequena deriva do tempo Unix é irrelevante.
Fusos horários e deslocamentos
Um timestamp Unix se refere a um único instante no tempo. Para exibi-lo de forma legível por humanos, você aplica um deslocamento de fuso horário. Deslocamentos comuns:
| Zona | Abreviação | Deslocamento do UTC | |------|-------------|---------------------| | Tempo Universal Coordenado | UTC | 0 | | Leste dos EUA (inverno) | EST | −5 | | Leste dos EUA (verão) | EDT | −4 | | Pacífico dos EUA (inverno) | PST | −8 | | Pacífico dos EUA (verão) | PDT | −7 | | Reino Unido (inverno) | GMT | 0 | | Reino Unido (verão) | BST | +1 | | Europa Central (inverno) | CET | +1 | | Europa Central (verão) | CEST | +2 | | Japão | JST | +9 | | China | CST | +8 | | Índia | IST | +5:30 | | Austrália (Sydney, inverno) | AEST | +10 | | Austrália (Sydney, verão) | AEDT | +11 |
Observe que Índia e China usam um único deslocamento durante todo o ano (sem horário de verão). Os EUA, Reino Unido e a maior parte da Europa observam DST, o que complica tudo.
Um bug comum: um servidor armazena um timestamp Unix (sempre UTC), depois o exibe sem aplicar o deslocamento local do usuário, e o usuário vê um horário com diferença de várias horas. Sempre armazene em UTC, sempre converta para local no momento da exibição.
O problema de 2038 em detalhes
O problema de 2038 (também conhecido como Y2K38) é o overflow de inteiro com sinal de 32 bits que ocorrerá em 2038-01-19 03:14:07 UTC. O segundo seguinte transborda para −2.147.483.648, que na maioria dos sistemas é interpretado como 1901-12-13 20:45:52 UTC. Qualquer coisa que dependa de timestamps Unix como inteiros com sinal de 32 bits quebrará:
- Sistemas de arquivos que armazenam mtime em time_t de 32 bits
- Bancos de dados antigos (MySQL antigo, alguns builds de SQLite)
- Sistemas embarcados (roteadores, dispositivos IoT, carros)
- Protocolos de rede que usam campos de tempo de 32 bits (NTP, DNS, Kerberos, alguns handshakes TLS)
Sistemas modernos (Linux de 64 bits, macOS de 64 bits, Windows moderno, bancos de dados modernos) já migraram para 64 bits. O risco está no código legado e embarcado que não foi atualizado.
A correção: mude o tipo de dado de `time_t` (32 bits) para `int64_t` (ou equivalente). Uma mudança de declaração, mais uma recompilação. O desafio é encontrar cada lugar onde a suposição de 32 bits vive — formatos de arquivo, protocolos de fio, dados persistidos, bibliotecas de terceiros.
Trabalhando com timestamps Unix em código
Python
O módulo `datetime` do Python é a ferramenta canônica.
```python import datetime from zoneinfo import ZoneInfo
# Timestamp Unix atual (segundos, float) import time now = time.time() # 1700000000.123
# Converter timestamp Unix para datetime (UTC) ts = 1700000000 utc = datetime.datetime.fromtimestamp(ts, tz=datetime.timezone.utc) # 2023-11-14 22:13:20+00:00
# Converter timestamp Unix para datetime (zona específica) ny = datetime.datetime.fromtimestamp(ts, tz=ZoneInfo("America/New_York")) # 2023-11-14 17:13:20-05:00
# Converter datetime para timestamp Unix d = datetime.datetime(2023, 11, 14, 22, 13, 20, tzinfo=datetime.timezone.utc) ts = int(d.timestamp()) # 1700000000
# Formatar como ISO 8601 print(utc.isoformat()) # 2023-11-14T22:13:20+00:00 ```
Cuidado: `datetime.fromtimestamp(ts)` (sem `tz`) usa o fuso horário local, que raramente é o que você quer em um contexto de servidor. Sempre passe um fuso horário explícito.
JavaScript
JavaScript usa milissegundos, não segundos. `Date.now()` retorna milissegundos desde a época.
```js // Timestamp Unix atual em milissegundos const now = Date.now(); // ex.: 1700000000000
// Timestamp Unix atual em segundos const nowSec = Math.floor(Date.now() / 1000);
// Converter segundos para milissegundos e criar um Date const date = new Date(1700000000 * 1000); // 2023-11-14T22:13:20.000Z
// Converter milissegundos para segundos const ts = Math.floor(date.getTime() / 1000);
// Exibir em um fuso horário específico com Intl console.log(date.toLocaleString("en-US", { timeZone: "Asia/Tokyo" })); // 11/15/2023, 7:13:20 AM
// ISO 8601 console.log(date.toISOString()); // 2023-11-14T22:13:20.000Z ```
A maior armadilha do JavaScript: todas as outras linguagens usam segundos; JavaScript usa milissegundos. Esquecer de multiplicar ou dividir por 1000 é a fonte de incontáveis bugs "fora por um fator de 1000".
SQL
A maioria dos bancos de dados suporta timestamps Unix nativamente ou através de funções.
```sql -- MySQL SELECT UNIX_TIMESTAMP(NOW()); -- timestamp atual (segundos) SELECT FROM_UNIXTIME(1700000000); -- 2023-11-14 22:13:20 SELECT FROM_UNIXTIME(1700000000, '%Y-%m-%d %H:%i:%s');
-- PostgreSQL SELECT EXTRACT(EPOCH FROM NOW()); -- timestamp atual (segundos, float) SELECT TO_TIMESTAMP(1700000000); -- 2023-11-14 22:13:20+00
-- SQLite SELECT strftime('%Y-%m-%dT%H:%M:%fZ', 'unixepoch', 1700000000); -- 2023-11-14T22:13:20.000Z ```
`UNIX_TIMESTAMP()` do MySQL retorna segundos; `EXTRACT(EPOCH FROM ...)` do PostgreSQL retorna segundos com precisão fracionária. SQLite requer a receita manual com `strftime`.
Bash
O comando `date` lida com timestamps Unix em todo sistema Unix.
```bash # Timestamp Unix atual date +%s # 1700000000
# Converter timestamp Unix para uma string de data # Linux (GNU date) date -d @1700000000 # Tue Nov 14 22:13:20 PM UTC 2023
# macOS (BSD date) date -r 1700000000 # Tue Nov 14 22:13:20 UTC 2023
# Converter uma string de data para timestamp Unix # Linux date -d "2023-11-14 22:13:20 UTC" +%s # macOS date -j -f "%Y-%m-%d %H:%M:%S" "2023-11-14 22:13:20" +%s
# Exibir em um fuso horário específico TZ="Asia/Tokyo" date -d @1700000000 # Wed Nov 15 07:13:20 JST 2023 ```
Para referência rápida: `date +%s` para "agora como tempo Unix" é um one-liner que você usará semanalmente.
Armazenando timestamps em bancos de dados
Melhores práticas para armazenamento em banco de dados:
- Armazene como inteiros (BIGINT): Timestamps Unix nativos são baratos de armazenar, fáceis de indexar, simples de comparar.
- Sempre use UTC: Converta para a zona local apenas no momento da exibição.
- Use BIGINT, não INT: Um inteiro com sinal de 32 bits transborda em 2038. Sempre use 64 bits.
- Considere precisão de milissegundos: Para logging de eventos de alta frequência (trading, gaming, telemetria), 1 segundo de resolução é muito grosseiro. Armazene como BIGINT milissegundos.
- Use TIMESTAMP WITH TIME ZONE: O `timestamptz` do PostgreSQL é o mais robusto. O `TIMESTAMP` do MySQL tem o problema de 2038; use `DATETIME` em vez disso.
- Indexe colunas de timestamp: Queries como `WHERE created_at > ?` são extremamente comuns. Um índice BTREE em uma coluna de timestamp as torna rápidas.
Um esquema comum:
```sql CREATE TABLE events ( id BIGSERIAL PRIMARY KEY, event_type TEXT NOT NULL, payload JSONB NOT NULL, created_at BIGINT NOT NULL, -- Unix ms INDEX idx_events_created (created_at) ); ```
Armadilhas comuns
O bug de milissegundos do JavaScript
Timestamps do JavaScript estão em milissegundos; todas as outras linguagens principais usam segundos. Misturá-los produz timestamps fora por um fator de 1000.
```js // De um backend Python const python_ts = 1700000000; // segundos const js_date = new Date(python_ts); // 1970-01-20T08:13:20.000Z ← ERRADO!
// Correto: multiplicar por 1000 const js_date = new Date(python_ts * 1000); ```
Bugs de exibição de fuso horário
Um timestamp se refere a um momento no tempo, não a uma data. Se seu servidor registra "2023-11-14 22:13:20" sem indicar UTC ou local, o usuário não tem como saber qual é. Sempre:
- Armazene como timestamp Unix (inerentemente UTC)
- Envie aos clientes com um fuso horário explícito
- Converta para local no momento da exibição usando o fuso real do usuário
```js // Servidor envia "2023-11-14T22:13:20Z" (Z = UTC) // Cliente renderiza no fuso local do usuário const d = new Date("2023-11-14T22:13:20Z"); console.log(d.toLocaleString()); // "11/14/2023, 5:13:20 PM" (em EST) ```
Casos extremos de DST
Um dia de 24 horas na primavera é na verdade 23 horas (DST pula uma hora); um dia de 24 horas no outono é 25 horas. Código que assume "adicionar 86.400 para obter amanhã" funciona bem; código que faz "adicionar 24 × 60 × 60" ou "amanhã às 2:30 AM" pode falhar nas transições de DST.
```python # Este é um dia de 23 ou 25 horas em zonas com DST d = datetime.datetime(2024, 3, 10, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")) # DST começa print((d + datetime.timedelta(days=1)).isoformat()) # 2024-03-11T01:00:00-05:00 ← correto print((d + datetime.timedelta(hours=24)).isoformat()) # 2024-03-11T02:00:00-04:00 ← DST pulou, isto é 25 horas depois ```
Para agendamento e matemática de hora do dia, prefira bibliotecas (Luxon, Arrow, date-fns) que tratam esses casos extremos corretamente.
Método 1: Use o conversor de timestamp do UtilBoxx (Recomendado)
Para conversões rápidas durante o desenvolvimento, o Conversor de Timestamp do UtilBoxx é uma ferramenta privada, no navegador, que converte entre timestamps Unix e datas em qualquer fuso horário, suporta tanto segundos quanto milissegundos, e roda inteiramente no cliente. Sem upload, sem cadastro, sem logs. Favorite-o para a próxima vez que precisar decodificar um timestamp desconhecido de uma resposta de API.
Conclusão
Timestamps Unix são simples, rápidos e universais — mas o ecossistema ao redor (fusos horários, segundos intercalares, o problema de 2038, confusão entre milissegundos e segundos) está cheio de armadilhas. Todo desenvolvedor eventualmente encontra cada uma delas; a única defesa é saber que elas existem.
Melhores práticas:
- Armazene como inteiros de 64 bits em UTC
- Converta para local no momento da exibição com o fuso horário real do usuário
- Use uma biblioteca de fuso horário real (Luxon, date-fns-tz, zoneinfo) para matemática de tempo não trivial
- Audite timestamps de 32 bits agora se você mantém código legado
Timestamps Unix são um dos formatos de dados mais antigos ainda em uso, e sobreviverão a todos nós — mas somente se os usarmos corretamente.