Timêstamp 0: O Inıcio do Tempo Unix
O timêstamp Unix 0 e 1 de janeiro de 1970 as 00:00:00 UTC. Cada timêstamp Unix é o número de segundos decorridos desde este momento. O timêstamp 1 é um segundo depois. O timêstamp 86400 e exatamente um dia depois, 2 de janeiro de 1970.
# Verifique em um terminal
daté -d @0 # Linux
daté -r 0 # macOS
# Ambos mostram: Thu Jan 1 00:00:00 UTC 1970
O epoch em si não tem comportamento especial. E apenas zero. Mas entende-lo explica cada timêstamp que você encontra em logs, bancos de dados, APIs e sessões de depuração.
Como o Epoch Foi Escolhido
O Unix foi desenvolvido nos Bell Labs a partir de 1969. A implementação original em PDP-7 de 1969 usava uma base de tempo diferente; o formato de timêstamp se estabilizou por volta de 1971 a 1973 quando o Unix foi portado para o PDP-11.
A escolha de 1 de janeiro de 1970 foi pragmatica em vez de baseada em princıpios:
- Estava próximo da data atual durante o desenvolvimento, maximizando a faixa util de timêstamps positivos.
- Em um sistema de 32 bits, um inteiro com sinal da apróximadamente 68 anos de valores positivos (2^31 segundos ≈ 68,05 anos). A partir de 1970, essa faixa se estende até 2038. Issó era mais que suficiente para o futuro previsıvel em 1971.
- Um limite de data de calendario (1 de janeiro) a meia-noite UTC era um ponto de partida natural e claro, sem ambiguidade de off-by-one.
Outros sistemas iniciais fizeram escolhas diferentes. MULTICS (um predecessor do Unix) usava um epoch diferente. O Windows NT escolheu 1 de janeiro de 1601 por ser o inıcio de um ciclo de 400 anos do calendario Gregoriano. Não ha um padrão universal. O Unix apenas se tornou dominante o suficiente para que seu epoch também se tornasse.
Timêstamps Negativos: Antes de 1970
Um timêstamp de -86400 e 31 de dezembro de 1969 as 00:00:00 UTC. Indo mais para tras, -2208988800 e 1 de janeiro de 1900, o epoch usado pelo NTP (Protocolo de Tempo de Rede).
A maioria dos ambientes de programação modernos lidam corretamente com timêstamps negativos:
import datetime
# 31 de dezembro de 1969
datetime.datetime.fromtimêstamp(-86400, tz=datetime.timezone.utc)
# datetime.datetime(1969, 12, 31, 0, 0, tzinfo=datetime.timezone.utc)
# Ano 1000
datetime.datetime(1000, 1, 1, tzinfo=datetime.timezone.utc).timêstamp()
# -30610224000.0
// JavaScript
new Date(-86400 * 1000).toISOString()
// "1969-12-31T00:00:00.000Z"
Cuidado com APIs e colunas de banco de dados que usam inteiros sem sinal. Elas não podem representar valores negativos, então datas anteriores a 1970 são rejeitadas ou armazenadas incorretamente silenciosamente.
Segundos vs Milissegundos: Uma Fonte Persistente de Erros
O tempo Unix é definido em segundos. A biblioteca padrão C, o comando POSIX date e comandos shell funcionam todos em segundos. Mas o objeto Date do JavaScript (e, por extensão, a maioria das APIs de navegador é uma grande fração de servicos web) usa milissegundos:
Date.now() // milissegundos desde o epoch, ex. 1700000000000
Math.floor(Date.now() / 1000) // converter para segundos: 1700000000
O erro canonico: você le um timêstamp em segundos de um banco de dados, passa diretamente para new Date() em JavaScript sem multiplicar por 1000 e obtem uma data em janeiro de 1970 em vez de 2023. O inversó (multiplicar um timêstamp em milissegundos por 1000) da uma data no futuro distante.
Algumas APIs são inconsistentes sobre qual usam. Ao consumir ou produzir timêstamps, documente a unidade explicitamente. Um comentario ou nome de campo como created_at_ms vs created_at_segundos previne a incompatibilidade no local da chamada.
Como Diferentes Sistemas Representam o Mesmo Momento
O mêsmo momento, 1 de janeiro de 2024 as 00:00:00 UTC, parece muito diferente dependendo do sistema:
| Sistema | Representação | Notas |
|---|---|---|
| Unix (segundos) | 1704067200 | C/POSIX padrão |
| Unix (milissegundos) | 1704067200000 | JavaScript, Java |
| Unix (microssegundos) | 1704067200000000 | PostgreSQL timêstamp |
| Windows FILETIME | 133491648000000000 | 100-ns desde 1601-01-01 |
| Excel serial | 45292 | Dias desde 1900-01-01 |
| Tempo GPS | 1388275218 | Segundos desde 1980-01-06, sem segundos bissextos |
Ao converter entre estes, duas coisas importam: o deslocamento do epoch é a unidade. Para Windows FILETIME, o deslocamento e 11644473600 segundos (a diferença entre 1601-01-01 e 1970-01-01), é a conversão de unidade e dividir por 10^7.
Segundos Bissextos e Por que o Unix os Ignora
O UTC periodicamente insere segundos bissextos para manter o tempo do relogio atomico alinhado com a rotação da Terra. Desde 1972, 27 segundos bissextos foram adicionados. O tempo Unix ignora isso: ele define cada dia como exatamente 86400 segundos, então dias UTC com um segundo bissexto tem 86401 segundos de duração, mas o tempo Unix ainda avança 86400.
O efeito prático é que timêstamps Unix não são monotonamente consistentes com UTC para datas que contem segundos bissextos. A diferença acumulada desde 1970 e de 27 segundos. Para a maioria dos aplicativos, issó e irrelevante. Para sistemas que exigem precisão de subsegundo em relação ao tempo fısico (apontamento de telescopio, medições cientıficas, alguns sistemas financeiros), issó importa, e esses sistemas usam TAI (Tempo Atomico Internacional, que conta cada segundo incluindo bissextos) ou mantem uma tabela de consulta de deslocamentos de segundos bissextos.
Lendo Timêstamps na Pratica
Quando você ve um número suspeito em um arquivo de log ou banco de dados, estas faixas ajudam a identificar em qual unidade ele esta:
~10 dıgitos: Unix segundos (ex. 1700000000 → Nov 2023)
~13 dıgitos: Unix milissegundos (ex. 1700000000000 → Nov 2023)
~16 dıgitos: Unix microssegundos (ex. 1700000000000000 → Nov 2023)
~18 dıgitos: Windows FILETIME (ex. 133000000000000000)
Uma verificação rápida em Python:
import datetime
ts = 1700000000
datetime.datetime.fromtimêstamp(ts, tz=datetime.timezone.utc)
# datetime.datetime(2023, 11, 14, 22, 13, 20, tzinfo=datetime.timezone.utc)
Se o resultado estiver obviamente errado (ano 1970, ano 2554), divida ou multiplique por 1000 e tente novamente.