Skip to content
Voltar ao blog
Tutoriais

O Que Contém Exatamente uma Coluna timestamp do PostgreSQL?

Um guia em linguagem simples sobre como o PostgreSQL armazena timestamp vs timestamptz, por que os fusos horários causam problemas e como escolher o tipo correto para seu caso de uso.

6 min de leitura

PostgreSQL timestamp vs timestamptz: o que é armazenado realmente por baixo dos panos?

O PostgreSQL mantém tanto timestamp quanto timestamptz como um único inteiro de 64 bits: o número de microssegundos desde 1970-01-01 00:00:00 UTC. A distinção emerge unicamente durante a formatação dos dados para consumo humano.

Por que confunde as pessoas?

  • Duas colunas, uma data… dois resultados de consulta diferentes
  • Sua app insere 2025-07-29 10:00, mas outra equipe vê 02:00
  • O frontend renderiza uma string ISO que não coincide com o log do backend

Duas latas de pêssego: uma simples, uma etiquetada

Tipo de dadoNome oficialValor armazenadoO que acontece no SELECT
timestamptimestamp sem fuso horáriocontagem de microssegundos brutaÉ retornado sem alteração — o Postgres nunca adivinha um fuso horário
timestamptztimestamp com fuso horáriomesma contagem de microssegundosO Postgres aplica a configuração TimeZone da sessão logo antes de enviar o texto

Analogia

  • timestamp = uma lata de pêssegos sem etiqueta de origem. Você sabe que é fruta, mas não sabe onde foi enlatada.
  • timestamptz = uma lata orgulhosamente carimbada “Feito em UTC+8.” Quem abri-la pode decidir se converte o painel nutricional.

Por baixo dos panos: é apenas um número enorme

2000-01-01 00:00:00 UTC  → 0
2000-01-01 00:00:01 UTC  → 1 000 000
  • Unidade: microssegundos (um milionésimo de segundo)
  • Faixa: 4713 a.C. – 294276 d.C. — aprovado pelo Indiana Jones
  • O armazenamento para timestamp e timestamptz é idêntico; a interpretação difere

Uma demonstração de 15 segundos

-- O cliente pensa em horário de Xangai
SET TimeZone = 'Asia/Shanghai';

CREATE TABLE demo (
  created_ts timestamp,
  created_tz timestamptz
);

INSERT INTO demo VALUES ('2025-07-29 10:00', '2025-07-29 10:00');
ConsultaResultadoPor quê
SELECT created_ts FROM demo;2025-07-29 10:00:00Valor bruto, sem cálculo de fuso horário
SELECT created_tz FROM demo;2025-07-29 10:00:00+08Etiqueta aplicada na saída
SET TimeZone = 'UTC'; e depois selecionar2025-07-29 02:00:00+00O mesmo instante, nova perspectiva

Aritmética de timestamps e intervalos

Um dos aspectos mais práticos dos timestamps do PostgreSQL é a aritmética de intervalos. Como ambos os tipos armazenam contagens de microssegundos, você pode adicionar e subtrair intervalos diretamente:

-- Adicionar 3 horas e 30 minutos
SELECT '2025-07-29 10:00'::timestamptz + INTERVAL '3 hours 30 minutes';
-- → 2025-07-29 13:30:00+08

-- Encontrar a diferença entre dois timestamps
SELECT '2025-07-30 09:00'::timestamptz - '2025-07-29 10:00'::timestamptz;
-- → 23:00:00  (um intervalo)

-- Extrair campos específicos
SELECT EXTRACT(EPOCH FROM '2025-07-29 10:00:00+08'::timestamptz);
-- → 1753768800  (timestamp Unix em segundos)

-- Truncar ao limite do dia (útil para agregações diárias)
SELECT date_trunc('day', '2025-07-29 15:42:19+08'::timestamptz);
-- → 2025-07-29 00:00:00+08

A função EXTRACT(EPOCH FROM ...) é particularmente útil quando você precisa passar timestamps para sistemas externos que esperam segundos de época Unix. Por outro lado, você pode converter uma época de volta para timestamp:

SELECT to_timestamp(1753768800);
-- → 2025-07-29 10:00:00+08  (em sessão Asia/Shanghai)

Um ponto sutil, mas importante: a aritmética de intervalos com timestamp (sem fuso horário) ignora completamente as transições de horário de verão, enquanto timestamptz as respeita. Isso significa que adicionar INTERVAL '1 day' a um valor timestamptz que cruza um limite de mudança de horário retornará corretamente o mesmo horário no relógio de parede — não exatamente 24 horas depois.

Considerações de indexação e desempenho

Tanto timestamp quanto timestamptz são armazenados como inteiros de 8 bytes, portanto não há diferença de desempenho entre eles para armazenamento ou indexação. Os índices B-tree funcionam de forma idêntica em ambos os tipos porque a comparação subjacente é simplesmente uma comparação de inteiros.

No entanto, há algumas considerações práticas:

  • Consultas de faixa: WHERE created_at > '2025-07-01' funciona eficientemente com um índice em qualquer um dos tipos. Com timestamptz, o PostgreSQL converte o literal para UTC antes da comparação, então o índice continua sendo usado.
  • Chaves de partição: Quando se usa particionamento por faixa em colunas timestamp, timestamptz é geralmente mais seguro porque os limites de partição são inequívocos (sempre UTC). Com timestamp, um limite como '2025-07-01 00:00' poderia significar coisas diferentes para sessões diferentes.
  • Índices funcionais: Se frequentemente consulta apenas por data (ignorando a hora), considere um índice em date_trunc('day', created_at) para acelerar as consultas de agregação diária.

Problemas comuns e soluções rápidas

1. Diferentes usuários, diferentes relógios

  • Causa: os clientes usam diferentes configurações TimeZone com timestamptz
  • Solução: mantenha tudo em timestamp + combine um fuso, ou force SET TimeZone = 'UTC' na inicialização da conexão

Um padrão comum no código de aplicação é definir o fuso horário uma vez na inicialização do pool de conexões:

-- Na sua configuração de conexão (ex., configuração do pool de pg)
SET timezone = 'UTC';

Isso garante que todas as sessões vejam a mesma representação UTC, e a camada de aplicação gerencia a conversão para hora local na exibição.

2. Armazenar “hora do relógio” mas escolher o tipo errado

  • Os calendários de negócio (horários de loja, prazos) devem usar timestamp
  • Os fluxos de trabalho transfronteiriços (pedidos, logs) devem armazenar UTC em timestamptz

O teste é simples: se a pergunta é “em que momento isso aconteceu?” use timestamptz. Se a pergunta é “o que o relógio de parede mostra?” use timestamp.

3. APIs que se desviam

  • Sempre envie timestamptz como strings ISO-8601 com o deslocamento (Z ou +08:00)
  • Deixe a interface do usuário formatar localmente

4. Comparar timestamps entre tipos

Misturar timestamp e timestamptz em comparações ou joins é uma fonte comum de bugs sutis:

-- Perigoso: o cast implícito aplica o fuso horário da sessão
SELECT * FROM orders o
JOIN schedules s ON o.created_tz = s.start_ts;
-- O PostgreSQL converte s.start_ts para timestamptz usando o fuso horário da sessão
-- Sessões diferentes podem obter resultados de join diferentes!

Solução: sempre converta explicitamente quando comparar entre tipos, ou padronize em um tipo por domínio.

5. Problemas padrão dos ORMs

Muitos ORMs (Django, SQLAlchemy, ActiveRecord) usam por padrão timestamp sem fuso horário. Revise seus arquivos de migração — se sua app atende usuários em múltiplos fusos horários, mude o padrão para timestamptz. No Django, defina USE_TZ = True nas configurações. No SQLAlchemy, use DateTime(timezone=True).

Tabela de referência rápida: qual devo usar?

Apenas calendário local → timestamp
Qualquer coisa global   → timestamptz (armazenar em UTC)
  • Relatórios financeiros, horários de aulas → timestamp
  • Registros de auditoria, pedidos de e-commerce → timestamptz

Verifique em segundos com o Go Tools

NecessidadeFerramentaComo fazer
Inspecionar o valor de época do SQLConversor de ÉpocaCole 1690622400, clique em Converter
Comparar dois fusos horários rapidamenteConversor de Fuso HorárioInsira 10:00 Asia/Shanghai
Ordenar JSON em massa com campos de tempoFormatador JSONSolte o payload, formate e examine

Todas as utilidades rodam completamente no seu navegador — os dados nunca saem da sua máquina.

Perguntas frequentes

Qual é a diferença entre timestamp e timestamptz no PostgreSQL?

timestamp (sem fuso horário) armazena um valor de data e hora como está, sem contexto de fuso horário. timestamptz (com fuso horário) converte a entrada para UTC ao armazenar e converte de volta para o fuso horário da sessão na recuperação. Use timestamptz em quase todos os casos — previne os erros relacionados a fusos horários em sistemas distribuídos.

O PostgreSQL realmente armazena o fuso horário no timestamptz?

Não — apesar do nome, o PostgreSQL não armazena o fuso horário em si. Converte a entrada para UTC e armazena unicamente o valor UTC (uma contagem de microssegundos desde 2000-01-01). Na recuperação, converte de UTC para o fuso horário especificado pela configuração timezone da sua sessão. A informação do fuso horário original é descartada.

Como mudo o fuso horário de uma sessão do PostgreSQL?

Execute SET timezone = 'America/New_York'; para mudar o fuso horário da sessão. Isso afeta como os valores timestamptz são exibidos e interpretados. Para padrões em nível de servidor, defina timezone no postgresql.conf. Sempre use nomes de fuso horário IANA (como Asia/Shanghai) em vez de abreviações (como CST) para evitar ambiguidades.

Devo usar timestamp ou timestamptz para armazenar tempos de eventos?

Use timestamptz para praticamente tudo — ações de usuário, chamadas de API, registros de auditoria e eventos agendados. Só use timestamp (sem fuso horário) para tempos abstratos que não estão ligados a um momento específico, como “a loja abre às 09:00” que significa 9 da manhã no fuso horário local, não um instante UTC específico.

Como o PostgreSQL lida com o horário de verão com timestamptz?

O PostgreSQL lida corretamente com o horário de verão ao usar timestamptz porque armazena tudo em UTC internamente. Quando você recupera um valor, o PostgreSQL converte de UTC usando as regras de horário de verão atuais para o fuso horário da sua sessão. Isso significa que o mesmo instante UTC armazenado mostra corretamente diferentes horas locais antes e depois de uma transição de horário de verão.

Para um guia completo sobre timestamps Unix — incluindo o tratamento de precisão, as melhores práticas de fuso horário e exemplos de código em JavaScript, Python e Go — consulte nosso Guia de Timestamp Unix.

Resumo

  • Ambos os tipos de tempo do Postgres são contadores de microssegundos; a etiqueta é toda a diferença
  • Escolher o errado significa timestamps confusos e cálculos quebrados
  • Teste, converta e verifique com as ferramentas certas para economizar horas de depuração

Artigos relacionados

Ver todos os artigos