O que o número significa
O timestamp Unix é a quantidade de segundos decorridos desde 00:00:00 de 1º de janeiro de 1970 em UTC. Esse instante se chama epoch, e o número que conta a partir dele é deliberadamente burro: não tem fuso, não tem calendário, não tem horário de verão, não tem idioma e não tem formato. É uma posição numa reta.
A burrice é justamente a utilidade. Dois servidores em continentes diferentes concordam
sobre 1700000000 sem precisar concordar sobre mais nada — nem sobre
dd/mm/aaaa contra mm/dd/aaaa, nem sobre em que dia começa a semana, nem sobre se o
relógio andou no domingo passado. Toda a complicação que as pessoas associam a data mora
na exibição desse número, nunca no número.
Daí sai a frase que evita a maior parte dos bugs de data, se você levar a sério: timestamp é um instante; data é a descrição de um instante. "14 de novembro de 2023, 19:13" não é um instante enquanto alguém não disser onde. A mesma hora de relógio é um momento diferente em São Paulo e em Manaus. O número é inequívoco; a frase nunca é.
Segundos ou milissegundos: o erro que chega em produção
É o motivo número um pelo qual alguém abre uma ferramenta como esta, e é pior do que
parece. 1700000000 é novembro de 2023. 1700000000000 também é
novembro de 2023 — o mesmo instante, em milissegundos. Nenhum dos dois dá erro. Passe o
valor em milissegundos para algo que espera segundos e você aterrissa no ano 55834;
passe o valor em segundos para algo que espera milissegundos e você aterrissa em 20 de
janeiro de 1970. Os dois estão errados, os dois são aceitos sem reclamação, e ninguém
descobre até um cliente reparar numa assinatura que vence daqui a 53 mil anos.
A confusão é tão fácil porque o ecossistema nunca combinou uma unidade. Uma lista curta e incompleta do que as ferramentas ao seu redor devolvem de fato:
| Origem | Unidade | Dígitos hoje |
|---|---|---|
JavaScript Date.now() | milissegundos | 13 |
Java System.currentTimeMillis() | milissegundos | 13 |
Python time.time() | segundos (float) | 10 |
Go Time.Unix() | segundos | 10 |
PHP time() | segundos | 10 |
PostgreSQL extract(epoch from …) | segundos | 10 |
JWT, campos exp e iat | segundos | 10 |
| Kafka, timestamp do registro | milissegundos | 13 |
| Stripe e a maioria das APIs REST | segundos | 10 |
Prefixo do ObjectId do MongoDB | segundos | 10 |
Repare no par que causa quase todo incidente real: um front-end em JavaScript que pensa
em milissegundos conversando com um back-end em Python ou Go que pensa em segundos, com
um fator mil escondido numa multiplicação que ninguém escreveu. O caso clássico é o JWT:
a especificação define exp em segundos, e jogar Date.now()
direto ali produz um token válido pelos próximos cinquenta milênios — o que é uma falha
de segurança, não um detalhe de formatação.
Aqui a unidade é deduzida da ordem de grandeza: abaixo de 1011 lemos segundos, até 1014 milissegundos, acima disso microssegundos. Os limites foram escolhidos porque nenhum timestamp real cai na sobreposição — 1011 segundos é o ano 5138. E a detecção aparece na tela em vez de ser aplicada em silêncio, porque existe um caso que a magnitude não resolve: um valor em milissegundos anterior a março de 1973 é idêntico a um valor em segundos de um futuro distante. Chutar calado ali seria pior do que não chutar.
Os quatro fusos do Brasil
O país não tem "o horário de Brasília". Tem quatro fusos legais, e a diferença entre eles é exatamente o que separa um timestamp certo de um errado em duas ou três horas:
| Offset | Onde | Identificador IANA |
|---|---|---|
| UTC-2 | Fernando de Noronha, Trindade, ilhas oceânicas | America/Noronha |
| UTC-3 | Sudeste, Sul, Nordeste, Goiás, DF, Tocantins, Pará, Amapá | America/Sao_Paulo, America/Fortaleza, America/Belem |
| UTC-4 | Amazonas (maior parte), Mato Grosso, Mato Grosso do Sul, Rondônia, Roraima | America/Manaus, America/Cuiaba |
| UTC-5 | Acre e o sudoeste do Amazonas | America/Rio_Branco, America/Eirunepe |
E esses offsets não são estáveis no tempo. O Acre foi UTC-5 até 2008, virou UTC-4 pela Lei 11.662, e voltou a UTC-5 em novembro de 2013 depois de um plebiscito. A mesma lei de 2008 puxou o oeste do Pará de UTC-4 para UTC-3. Uma data de 2010 em Rio Branco, convertida com a regra de hoje, erra uma hora inteira — e ninguém percebe, porque o resultado continua parecendo uma data plausível.
Vale um aviso de código: America/Brasilia não existe. O identificador IANA da
hora de Brasília é America/Sao_Paulo, e escrever o outro dá erro em tempo de
execução em Java, Python, PostgreSQL e no Intl do navegador.
O horário de verão acabou em 2019 — e por isso 2015 importa
O horário de verão brasileiro foi extinto pelo Decreto 9.772, de 25 de abril de 2019. O último período válido foi de 4 de novembro de 2018 a 16 de fevereiro de 2019. De lá para cá, o país inteiro fica no mesmo offset o ano todo.
Só que isso não apaga o passado. Uma data de janeiro de 2015 em São Paulo estava em UTC-2, não em UTC-3, porque havia horário de verão em vigor — ele começou em 19 de outubro de 2014 e terminou em 22 de fevereiro de 2015, com a data de término adiada uma semana por causa do Carnaval, como acontecia sempre que os dois colidiam. Quem soma -3 na mão erra uma hora em toda data de verão anterior a 2019. É um erro pequeno o bastante para passar despercebido e grande o bastante para trocar o dia numa conversão perto da meia-noite.
Pior: o horário de verão nunca valeu para o país inteiro. Aplicava-se ao Sul, ao Sudeste e ao Centro-Oeste; o Norte e o Nordeste ficaram de fora nas últimas décadas, com a Bahia entrando em 2011 e saindo em 2012. Ou seja, no mesmo mês de janeiro de 2015, São Paulo estava em UTC-2 e Fortaleza em UTC-3 — a diferença entre as duas cidades era de uma hora, apesar de as duas serem "horário de Brasília" no resto do ano.
Nada disso está codificado aqui à mão. As conversões perguntam ao
Intl.DateTimeFormat do próprio navegador, que carrega a base IANA completa,
com o histórico. É a diferença entre uma ferramenta que acerta 2015 e uma que acerta
apenas hoje. Duas consequências práticas que a ferramenta mostra na tela: quando o
relógio adianta, existe uma hora de parede que nunca aconteceu; quando atrasa,
existe uma que aconteceu duas vezes. Nos dois casos o resultado é sinalizado em
vez de escolhido em silêncio.
Guarde UTC, formate na borda
A regra prática que sai de tudo isso: mantenha um instante num lugar só, em UTC, e
converta para fuso humano apenas no momento de exibir. No banco, use
timestamptz (que o PostgreSQL armazena em UTC) e não
timestamp sem fuso, que guarda uma hora de parede solta e não significa nada
sem contexto externo. Nunca guarde a data já formatada em texto.
O motivo é que offset vence. "17/02/2018 23:30 com offset -02:00" é um fato verdadeiro para sempre, mas exige recalcular o instante a cada leitura. "17/02/2018 23:30, Brasil" é um dado que muda de significado quando o governo muda a regra — e o governo mudou em 2019. Um instante em UTC nunca muda de significado; todo o resto é uma vista dele.
A exceção legítima é o evento futuro em hora local. Uma reunião marcada para as 09:00 de março do ano que vem quer dizer "o que quer que 09:00 venha a ser", então o correto é guardar a hora de parede mais o identificador do fuso — não o offset. Isso é agenda, não log.
O problema do ano 2038
Em 19 de janeiro de 2038, às 03:14:07 UTC, o tempo Unix chega a 2147483647. Esse é 231−1, o maior número que cabe num inteiro de 32 bits com sinal. Um segundo depois o contador transborda para o bit de sinal e vira −2147483648, que se lê como 13 de dezembro de 1901. Um relógio que contou para a frente por 68 anos cai 136 anos para trás num único tique.
Não é curiosidade teórica e não é o bug do milênio de novo. O Y2K era convenção de
formatação — dois dígitos para o ano. O 2038 é transbordamento aritmético num tipo de
dado, o que é um problema de natureza diferente e bem menos fácil de contornar com
heurística. Máquinas de 64 bits estão resolvidas há anos: um contador de segundos com
sinal de 64 bits só estoura por volta do ano 292 bilhões. Mas o problema nunca foi de
processador. Ele mora onde a largura de 32 bits está congelada em algo difícil de trocar:
formato de arquivo em disco (o timestamp do inode do ext3), protocolo de rede, a coluna
TIMESTAMP do MySQL, firmware embarcado em medidor, controlador industrial e
carro com vinte anos de vida útil, e todo código que um dia converteu um tempo para
int porque parecia obviamente grande o suficiente.
E já está acontecendo em doses pequenas: qualquer cálculo de vencimento a 20 anos cruzou a fronteira em 2018 — sistemas de certificado digital e de financiamento imobiliário bateram nela primeiro. Se você digitar um timestamp além do limite, esta ferramenta avisa, porque "isto ainda cabe em 32 bits?" é uma pergunta que vale fazer de qualquer sistema que você ainda vai manter.
Timestamp negativo: antes de 1970
Nada na definição impede a contagem de andar para trás. −1 é 31 de dezembro de 1969 às 23:59:59 UTC. −2208988800 é 1º de janeiro de 1900. São valores comuns em data de nascimento, acervo histórico, genealogia e qualquer base com registros anteriores a 1970.
Também são o ponto em que muita ferramenta desmonta em silêncio: conversor que recusa o sinal de menos, que mostra o valor absoluto como uma data de 1971, ou que perde uma hora porque aplicou o offset do fuso no sentido contrário. Sistemas antigos usavam um inteiro de 32 bits sem sinal e simplesmente não conseguiam expressar nada antes de 1970. Aqui a entrada negativa é tratada como qualquer outra, e o resultado é marcado como anterior à epoch — para que um sinal de menos digitado por engano fique visível em vez de apenas plausível.
Segundo bissexto: o que o tempo Unix ignora de propósito
A rotação da Terra é irregular, então o UTC é corrigido de vez em quando com a inserção de um segundo bissexto — um minuto real de 61 segundos, 23:59:60, acrescentado 27 vezes desde 1972. O tempo Unix não representa nenhum deles. Ele define que todo dia tem exatamente 86400 segundos, sempre.
Ou seja: o tempo Unix não é uma contagem verdadeira de segundos decorridos. Está uns 27 segundos atrás da contagem física e vai ficando. A troca é deliberada e, no saldo, certa: como todo dia tem o mesmo tamanho, converter entre timestamp e data de calendário é divisão pura, sem tabela de segundos bissextos para consultar, sem tabela para manter atualizada e sem dúvida sobre qual versão da tabela uma máquina específica tem.
O que cada sistema operacional faz no momento da inserção varia: alguns repetem o mesmo valor Unix por dois segundos seguidos, e os grandes provedores de nuvem "borram" o segundo extra ao longo de várias horas, para que nenhum relógio ande para trás. Nos dois casos, durante um segundo bissexto o timestamp deixa de identificar um instante único — o que já derrubou serviço de verdade e é um bom argumento contra usar timestamp como chave única.
Como esta ferramenta funciona e o que ela não faz
Tudo roda no seu navegador. Não há requisição, nada é enviado e nada fica guardado. A
aritmética mora num módulo separado, sem acesso à página, justamente para poder ser
testada fora do navegador; as regras de fuso vêm do Intl.DateTimeFormat, que
já traz a base IANA histórica completa.
- Faixa. As datas do JavaScript cobrem cerca de ±273.000 anos em torno da epoch. Fora dessa janela a ferramenta devolve erro em vez de chutar.
- Precisão. Microssegundos são aceitos e exibidos, mas o instante é guardado internamente em milissegundos, então os dígitos abaixo do milissegundo são truncados, não preservados. Nanossegundo exigiria aritmética com BigInt, que esta ferramenta não faz.
- Offsets históricos com segundos. São Paulo era UTC-03:06:28 antes de 1914, no tempo médio local. Esses offsets são arredondados para o minuto, porque nenhum formato de data comum consegue expressar os segundos.
- Segundo bissexto. Não é representado — exatamente como o próprio tempo Unix não o representa.
Perguntas frequentes
1700000000 está em segundos ou em milissegundos?
Em segundos: é 14 de novembro de 2023, às 22:13:20 UTC. O mesmo instante em milissegundos é 1700000000000, com três dígitos a mais. O teste rápido é contar dígitos: hoje um timestamp tem 10 dígitos em segundos, 13 em milissegundos e 16 em microssegundos. Esta ferramenta detecta pela ordem de grandeza, mostra na tela qual unidade assumiu e deixa você trocar à mão quando o palpite estiver errado.
Por que a mesma data me dá dois timestamps diferentes?
Porque data e hora sem fuso não são um instante. 14/11/2023 às 19:13 vira 22:13 UTC se você quis dizer São Paulo e 21:13 UTC se quis dizer Manaus — três e quatro horas de diferença a partir dos mesmos caracteres digitados. Por isso o seletor de fuso desta página vale para os dois sentidos e o resultado sempre informa o offset que foi aplicado.
O Brasil ainda tem horário de verão?
Não. O horário de verão foi extinto pelo Decreto 9.772, de 25 de abril de 2019, e o último período válido foi de 4 de novembro de 2018 a 16 de fevereiro de 2019. Isso NÃO significa que você pode ignorá-lo: converter uma data de 2015, 2010 ou 1990 no fuso de São Paulo continua exigindo a regra que valia naquele ano. É por isso que esta ferramenta usa a base IANA do navegador em vez de somar -3 na mão.
Timestamp negativo é válido?
É. Valores negativos são instantes anteriores a 1º de janeiro de 1970, contando para trás: -1 é 31/12/1969 às 23:59:59 UTC e -2208988800 é 1º de janeiro de 1900. Aparecem o tempo todo em data de nascimento e em registro histórico, e uma quantidade surpreendente de conversores ou rejeita o sinal ou mostra o valor absoluto como se fosse 1971. Este trata como entrada comum e marca o resultado como anterior à epoch.
Qual fuso eu uso em código: America/Sao_Paulo ou America/Brasilia?
America/Sao_Paulo. America/Brasilia não existe na base IANA e provoca erro em tempo de execução em Java, Python, PostgreSQL e no Intl do navegador. Os identificadores brasileiros são America/Sao_Paulo, America/Bahia, America/Fortaleza, America/Recife, America/Belem, America/Araguaina, America/Campo_Grande, America/Cuiaba, America/Manaus, America/Boa_Vista, America/Porto_Velho, America/Rio_Branco, America/Eirunepe, America/Santarem, America/Maceio e America/Noronha.