Coding Interview Prep · Aula

Fusos horários e marcas de data e hora

Armazenando UTC, convertendo fusos e entendendo as armadilhas sobre marcas de data e hora levantadas por entrevistadores.

Aula 4 de 413 etapas

Fusos horários e marcas de data e hora é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Coding Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Coding Interview Prep inclui 4 aulas no total.

Por que os fusos horários confundem os candidatos

Os fusos horários são um ponto em que candidatos confiantes tropeçam, por isso os entrevistadores os exploram para avaliar a profundidade do conhecimento. A pergunta central é sempre: “como você armazena e compara carimbos de data e hora entre regiões?”

A resposta profissional é uma prática disciplinada, não uma função: armazene tudo em UTC e converta apenas nas extremidades, para exibição. Com o modelo de armazenamento correto, a maioria das consultas se torna trivial.

  • carimbo de data e hora vs carimbo de data e hora com fuso horário
  • Conversão entre fusos
  • UTC como fonte de verdade

Carimbo de data e hora vs carimbo de data e hora com fuso horário

O PostgreSQL tem dois tipos de carimbo de data e hora, e confundi-los é um erro comum em entrevistas.

  • timestamp (sem fuso horário): um valor do relógio local sem fuso associado. Ele armazena exatamente o valor fornecido.
  • timestamptz (com fuso horário): armazenado internamente como UTC; na entrada, é convertido a partir do fuso da sessão e, na saída, é convertido novamente.

Apesar do nome, timestamptz não armazena um fuso; ele armazena um instante preciso em UTC. Esse detalhe impressiona os entrevistadores.

CREATE TABLE events (
  id          bigint,
  occurred_at timestamptz   -- recommended: an absolute instant
);

Armazene em UTC e converta nas extremidades

A regra de ouro. Armazene os instantes em UTC (use timestamptz) e converta para um fuso local somente ao apresentá-los a um usuário. Isso evita ambiguidades relacionadas ao horário de verão e faz com que a ordenação por horário esteja correta em todos os lugares.

Se perguntarem “por que UTC?”, responda: UTC não tem mudanças para o horário de verão, portanto o mesmo horário local nunca se repete nem é pulado, ao contrário do horário local.

-- Display a UTC instant in a user's zone (Postgres)
SELECT occurred_at AT TIME ZONE 'America/New_York' AS local_time
FROM events;

O duplo significado de AT TIME ZONE

AT TIME ZONE é uma construção inteligente e uma armadilha frequente, porque faz duas coisas opostas dependendo do tipo de entrada:

  • Quando aplicado a um timestamptz, converte o instante absoluto para esse fuso e retorna um timestamp simples (o horário local exibido pelo relógio).
  • Quando aplicado a um timestamp simples, ele interpreta esse horário local como pertencente a esse fuso e retorna um timestamptz.

Entender em que direção ele funciona é todo o segredo.

-- timestamptz -> local wall clock (returns timestamp)
SELECT TIMESTAMPTZ '2024-03-01 12:00:00+00'
         AT TIME ZONE 'Asia/Tokyo';        -- 2024-03-01 21:00:00

-- plain timestamp interpreted in a zone (returns timestamptz)
SELECT TIMESTAMP '2024-03-01 12:00:00'
         AT TIME ZONE 'Asia/Tokyo';        -- 2024-03-01 03:00:00+00

Obtendo o instante atual

Conheça suas funções de "agora". NOW() e CURRENT_TIMESTAMP retornam um timestamptz no Postgres. Elas retornam o horário do início da transação, não da instrução, o que é importante em transações longas.

Para obter UTC explicitamente, faça a conversão: NOW() AT TIME ZONE 'UTC'. No MySQL, UTC_TIMESTAMP() fornece UTC diretamente.

SELECT
  NOW()                       AS tx_start_tz,
  NOW() AT TIME ZONE 'UTC'    AS utc_walltime;

O horário de verão é o verdadeiro inimigo

Entrevistadores adoram casos extremos de DST. Quando os relógios avançam, uma hora do relógio local não existe; quando retrocedem, uma hora se repete. Armazenar a hora local torna esses casos ambíguos ou inválidos.

Armazenar UTC evita completamente esse problema: cada instante é único e monotônico. Especificar uma região como 'America/New_York' (e não um deslocamento fixo como -05:00) permite que o banco de dados aplique corretamente as regras de DST para qualquer data.

-- Region name applies DST automatically for the given date
SELECT TIMESTAMPTZ '2024-07-01 12:00:00+00'
         AT TIME ZONE 'America/New_York' AS summer, -- EDT (-04)
       TIMESTAMPTZ '2024-01-01 12:00:00+00'
         AT TIME ZONE 'America/New_York' AS winter; -- EST (-05)

Agrupando por dia local entre fusos horários

Um problema realista: "usuários ativos diariamente no horário local de cada usuário". Se você truncar diretamente o carimbo de data e hora em UTC, os limites da meia-noite ficarão errados para usuários fora de UTC.

Converta para o fuso do usuário antes de truncar para o dia. A conversão desloca o horário local para que os limites do dia fiquem alinhados localmente.

SELECT
  DATE_TRUNC('day', occurred_at AT TIME ZONE u.tz) AS local_day,
  COUNT(DISTINCT e.user_id)                         AS dau
FROM events e
JOIN users u ON u.id = e.user_id
GROUP BY 1
ORDER BY 1;

Comparando carimbos de data e hora com segurança

Ao filtrar uma coluna timestamptz, compare-a com um instante explícito, de preferência um literal em UTC ou um timestamptz com deslocamento. Comparar com uma string isolada pode fazer com que ela seja interpretada no fuso imprevisível da sessão.

Assim, a comparação permanece sem ambiguidades, independentemente de quem execute a consulta.

SELECT *
FROM events
WHERE occurred_at >= TIMESTAMPTZ '2024-03-01 00:00:00+00'
  AND occurred_at <  TIMESTAMPTZ '2024-04-01 00:00:00+00';

Época e carimbos Unix

Muitos sistemas armazenam o horário como uma época Unix (segundos desde 1970-01-01 UTC). Entrevistadores podem fornecer uma coluna de inteiros e pedir que você a interprete.

  • Postgres: TO_TIMESTAMP(epoch_seconds) retorna um timestamptz.
  • De volta à época: EXTRACT(EPOCH FROM occurred_at).
  • MySQL: FROM_UNIXTIME() e UNIX_TIMESTAMP().

Os valores de época são inerentemente UTC, o que explica em parte sua popularidade para armazenamento.

SELECT
  TO_TIMESTAMP(1709294400)               AS as_ts,   -- from epoch
  EXTRACT(EPOCH FROM NOW())::bigint        AS as_epoch; -- to epoch

Observações sobre fusos horários entre dialetos

Um resumo rápido para que você demonstre domínio em qualquer ambiente:

  • Postgres: timestamptz + AT TIME ZONE, com o suporte mais completo.
  • MySQL: TIMESTAMP converte automaticamente por meio de time_zone da sessão; CONVERT_TZ(t, from, to) faz a conversão explicitamente. DATETIME não reconhece fusos horários.
  • SQL Server: datetimeoffset armazena um deslocamento; AT TIME ZONE 'name' faz a conversão usando os nomes de fusos do Windows.
-- MySQL explicit conversion
SELECT CONVERT_TZ(event_dt, 'UTC', 'Europe/Istanbul') AS local_dt
FROM events;

Exemplo mais detalhado: sessões que atravessam a meia-noite

Uma questão sutil de relatórios: contabilizar sessões por dia do calendário local quando uma sessão pode atravessar a meia-noite. A solução segue a mesma disciplina: converta para a hora local e depois agrupe.

Armazene o início e o fim como timestamptz; nos relatórios, derive o dia local a partir do início convertido. Se uma sessão precisar ser dividida entre dois dias, você poderá fazer uma junção com uma sequência de dias, um ótimo ponto para mencionar como pergunta complementar.

SELECT
  DATE_TRUNC('day', started_at AT TIME ZONE 'Europe/Istanbul') AS local_day,
  COUNT(*) AS sessions
FROM sessions
GROUP BY 1
ORDER BY 1;

Verificação rápida

Confirme a estratégia de armazenamento recomendada e o motivo.

Resumo: fusos horários e carimbos de data e hora

A disciplina que você deve levar consigo:

  • Armazene UTC como timestamptz; converta para um fuso identificado por nome somente para exibição.
  • timestamptz armazena um instante UTC, não um fuso, apesar do nome.
  • AT TIME ZONE funciona em ambas as direções, dependendo do tipo de entrada: converte um timestamptz para o horário local ou interpreta um timestamp simples como pertencente a um fuso.
  • Use nomes de regiões ('America/New_York') para que o DST seja aplicado automaticamente; evite deslocamentos fixos.
  • Converta para a hora local antes de truncar para um dia e compare as colunas com instantes UTC explícitos.
Grátis para começar

Aprenda Coding Interview Prep com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
90
Aulas
360

Perguntas Frequentes

A aula “Fusos horários e marcas de data e hora” é grátis?

Sim — o texto completo de “Fusos horários e marcas de data e hora” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Coding Interview Prep, atualize para CoddyKit PRO. O curso de Coding Interview Prep inclui 4 aulas no total.

O que vou aprender em “Fusos horários e marcas de data e hora”?

Armazenando UTC, convertendo fusos e entendendo as armadilhas sobre marcas de data e hora levantadas por entrevistadores. Você pratica Coding Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Coding Interview Prep?

Nenhuma experiência prévia é necessária. Coding Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Fusos horários e marcas de data e hora”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Coding Interview Prep?

Sim. Cada aula de Coding Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Aritmética de datas e intervalos
  2. Truncando e agrupando datas
  3. Analisando e formatando strings
  4. Fusos horários e marcas de data e hora
← Voltar para Coding Interview Prep