sqlpostgresqldatesinterval

make_timestamp e make_interval no SQL: montar datas e intervalos por partes

make_timestamp monta uma data a partir de numeros e make_interval cria um intervalo com argumentos nomeados em vez de concatenar strings.

3 min de leituraReferencesql · postgresql · dates · interval · timestamp

Quando uma data chega como numeros soltos — um ano, um mes e um dia de um formulario ou de colunas de relatorio — e tentador colar uma string e converte-la para timestamp. O PostgreSQL oferece uma alternativa honesta: make_timestamp e make_interval constroem o valor direto a partir de numeros, sem strings de formato e sem adivinhar locale.

Uma data a partir de partes numericas

make_timestamp recebe ano, mes, dia, hora, minuto e segundos como numeros comuns e devolve um timestamp. Sem parsear strings, nao ha surpresa com a ordem MM/DD contra DD/MM.

SELECT make_timestamp(2024, 3, 15, 14, 30, 0) AS ts;
-- 2024-03-15 14:30:00

Os segundos sao double precision, entao valores fracionarios tambem funcionam: make_timestamp(2024, 3, 15, 14, 30, 7.5). Ha parentes proximos: make_date(2024, 3, 15) para uma data pura e make_time(14, 30, 0) para uma hora do dia.

Compare com a concatenacao usual de strings, fragil e dependente da sessao:

-- fragile: depends on DateStyle and zero-padding
SELECT (y || '-' || m || '-' || d)::date FROM (SELECT 2024 y, 3 m, 15 d) s;

Se m for 3 em vez de 03, ou se DateStyle estiver em DMY, esse codigo devolve em silencio a data errada ou falha. make_timestamp elimina os dois modos de falha de uma vez.

Um intervalo a partir de argumentos nomeados

make_interval constroi um interval com campos nomeados: years, months, weeks, days, hours, mins, secs. Passe apenas o que precisar; o resto e zero por padrao.

SELECT make_interval(days => 10, hours => 2) AS shipping_window;
-- 10 days 02:00:00

O grande ganho e a parametrizacao. Quando a quantidade e um numero variavel, voce nao consegue coloca-la dentro de um literal INTERVAL de string, mas consegue passa-la direto para make_interval:

-- give every paid order a grace period of N days
SELECT o.id,
       o.created_at + make_interval(days => 14) AS grace_until
FROM orders o
WHERE o.status = 'paid';

Esse 14 pode ser uma coluna ou um marcador $1. Essa e a diferenca chave em relacao a um intervalo de string: INTERVAL '$1 days' nao funciona porque o marcador ficaria dentro do literal, enquanto make_interval(days => $1) faz o bind corretamente.

-- per-row interval driven by data, not a constant string
SELECT u.id, u.email,
       u.created_at + make_interval(days => 30) AS trial_ends
FROM users u
WHERE u.country = 'DE';

make_timestamptz e o fuso horario

make_timestamp tem um irmao com fuso, make_timestamptz. Um argumento de texto extra nomeia o fuso em que os numeros fornecidos sao interpretados; o resultado e um timestamptz.

SELECT make_timestamptz(2024, 3, 15, 14, 30, 0, 'Europe/Berlin') AS ts_tz;
-- stored as UTC, shown in your session zone

Sem o ultimo argumento os numeros sao lidos no fuso da sessao atual (TimeZone). Isso e pratico para prazos ancorados a uma regiao especifica:

SELECT u.id,
       make_timestamptz(2024, 12, 31, 23, 59, 59, 'America/Sao_Paulo') AS cutoff
FROM users u
WHERE u.country = 'BR';

Pegadinha: os argumentos de make_* nao transbordam para frente. make_timestamp(2024, 13, 1, 0, 0, 0) nao vira janeiro de 2025 — ele levanta field value out of range. O mesmo vale para make_date(2024, 2, 30). Se as entradas sao numeros nao confiaveis, valide antes ou capture a excecao.

Diferencas em outros bancos

make_timestamp, make_interval e companhia sao do PostgreSQL. Outros bancos seguem caminho diferente:

  • MySQL: monte a data com MAKEDATE/MAKETIME ou STR_TO_DATE('2024-03-15','%Y-%m-%d'). Intervalos usam a sintaxe INTERVAL 10 DAY, e para uma quantidade variavel voce escreve INTERVAL n DAY, onde n pode ser uma expressao.
  • ClickHouse: use makeDateTime(2024, 3, 15, 14, 30, 0) e makeDateTime64(...) para precisao de fracao de segundo; o fuso e um argumento separado. Construa um intervalo com toIntervalDay(n), toIntervalHour(n) e some-os.

Se o codigo precisa ser portavel, isole a montagem de datas em uma unica camada: a familia make_* no PostgreSQL, funcoes nativas no resto. O principio central e o mesmo em todo lugar: nao cole datas a partir de strings quando o banco sabe construi-las a partir de numeros.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador