CodeGym /Cursos /SQL SELF /Trabalhando com fusos horários: TIMEZONE

Trabalhando com fusos horários: TIMEZONE

SQL SELF
Nível 32 , Lição 2
Disponível

Imagina que tu tem um app de reserva de passagens aéreas. O voo sai de Nova York às 10:00 no horário local e chega em Londres às 22:00 no horário local. Se tu ignorar os fusos horários, teu servidor pode fazer uma bagunça total, mostrando o horário de chegada todo errado.

Fusos horários são teus melhores amigos (ou os piores inimigos, quando dá ruim). Se teus usuários estão em países diferentes ou tu precisa lidar com agendas que dependem do horário local (tipo horário de voos ou eventos), então prestar atenção nos fusos horários é fundamental.

Tipos de dados de tempo

A gente já falou que existem dois tipos de dados pra trabalhar com marcações de tempo:

  • TIMESTAMP: data e hora sem considerar fuso horário.
  • TIMESTAMPTZ: data e hora considerando fuso horário.

Bora ver de novo com um exemplo.

-- Criando uma tabela com duas colunas: TIMESTAMP e TIMESTAMPTZ
CREATE TABLE flight_schedule (
    flight_id SERIAL PRIMARY KEY,
    departure_time TIMESTAMP,
    departure_time_with_tz TIMESTAMPTZ
);

-- Inserindo dados
INSERT INTO flight_schedule (departure_time, departure_time_with_tz)
VALUES
    ('2023-10-25 10:00:00', '2023-10-25 10:00:00+00');

-- Conferindo os dados
SELECT * FROM flight_schedule;

O resultado vai depender do fuso horário do teu servidor. Por exemplo:

flight_id departure_time departure_time_with_tz
1 2023-10-25 10:00:00 2023-10-25 10:00:00+00

A diferença chave:

  • A coluna departure_time só guarda a data e hora sem ligar pra nenhum fuso horário.
  • A coluna departure_time_with_tz guarda a data e hora junto com a info do fuso (+00 nesse caso).

Convertendo horários entre fusos

Pra trabalhar com fusos horários no PostgreSQL, tu usa a função AT TIME ZONE.

Convertendo UTC pra horário local

Imagina que tu tem uma marcação de tempo em UTC (tempo universal coordenado). Tu quer mostrar isso pra um usuário que tá no fuso America/New_York.

SELECT
    '2023-10-25 14:00:00+00'::TIMESTAMPTZ AT TIME ZONE 'America/New_York' AS local_time;

Resultado:

local_time
2023-10-25 10:00:00

AT TIME ZONE aqui é tipo mágica: converte o horário de UTC pro fuso que tu pediu.

Convertendo horário local pra UTC

Agora imagina o contrário: tu tem um horário em America/New_York e quer converter pra UTC.

SELECT
    '2023-10-25 10:00:00'::TIMESTAMP AT TIME ZONE 'America/New_York' AS utc_time;

Resultado:

utc_time
2023-10-25 14:00:00+00

Repara que o resultado vai ser no formato TIMESTAMPTZ, porque inclui a info do fuso (UTC nesse caso).

Trabalhando com o tipo TIMESTAMPTZ

Quando tu usa TIMESTAMPTZ, o PostgreSQL já leva em conta o fuso do teu servidor (ou o que tu definir).

Tu pode definir o fuso da sessão atual com o comando:

SET TIMEZONE = 'Europe/Istanbul';

Depois disso, tudo que tu fizer com TIMESTAMPTZ vai considerar esse fuso.

Exemplo: inserindo e buscando dados

-- Definindo o fuso horário
SET TIMEZONE = 'Europe/Istanbul';

-- Inserindo dados
INSERT INTO flight_schedule (departure_time_with_tz)
VALUES ('2023-10-25 10:00:00+00');

-- Conferindo os dados
SELECT departure_time_with_tz FROM flight_schedule;

Resultado no fuso Europe/Istanbul:

departure_time_with_tz
2023-10-25 13:00:00+03

O PostgreSQL converte automaticamente o horário de UTC pro fuso que tu definiu.

Exemplos práticos

Levando em conta fusos horários em agendas. Imagina que tu tem uma tabela com o cronograma de voos, e cada registro guarda o horário de saída em UTC. Tu quer mostrar o horário de saída pra cada voo já convertido pro horário local.

SELECT
    flight_id,
    departure_time_with_tz AT TIME ZONE 'America/New_York' AS local_time
FROM flight_schedule;

Comparando horários de diferentes fusos. Imagina que tu tá comparando dois eventos que rolaram em cidades diferentes. O PostgreSQL deixa tu fazer isso de boa, convertendo tudo pro mesmo fuso por baixo dos panos.

SELECT
    '2023-10-25 10:00:00+03'::TIMESTAMPTZ > '2023-10-25 07:00:00+00'::TIMESTAMPTZ AS event_one_later;

Resultado:

event_one_later
t

A comparação deu true, porque 10:00+03 é igual a 07:00+00.

Dicas e pegadinhas comuns

Lidar com horário é traiçoeiro. Olha o que costuma dar ruim:

  • Usam TIMESTAMP em vez de TIMESTAMPTZ e depois ficam bolados porque o horário não bate — porque o fuso simplesmente é ignorado.
  • Nem sabem em que fuso o servidor tá rodando, aí os dados são inseridos num horário e lidos em outro.
  • Erram o nome do fuso quando usam AT TIME ZONE — aí dá erro ou retorna o horário errado.

Pra não cair nessas:

  • Quase sempre usa TIMESTAMPTZ, principalmente se o dado pode depender do fuso.
  • Guarda o horário em UTC e só converte pro fuso do usuário na hora de mostrar.
  • Se quiser se aprofundar, dá uma olhada na documentação oficial do PostgreSQL sobre tempo e fusos — vale muito a pena.
2
Tarefa
SQL SELF, nível 32, lição 2
Bloqueado
Conversão de UTC para o fuso horário de Nova York
Conversão de UTC para o fuso horário de Nova York
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION