sqlpostgresqldatesinterval

make_timestamp y make_interval en SQL: construir fechas e intervalos por partes

make_timestamp arma una fecha a partir de numeros y make_interval construye un intervalo con argumentos con nombre en lugar de concatenar cadenas.

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

Cuando una fecha llega como numeros sueltos — un ano, un mes y un dia de un formulario o de columnas de un reporte — es tentador pegar una cadena y convertirla a timestamp. PostgreSQL ofrece una alternativa honesta: make_timestamp y make_interval construyen el valor directamente desde numeros, sin cadenas de formato ni adivinanzas de locale.

Una fecha a partir de partes numericas

make_timestamp recibe ano, mes, dia, hora, minuto y segundos como numeros normales y devuelve un timestamp. Al no parsear cadenas no hay sorpresas con el orden MM/DD frente a DD/MM.

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

Los segundos son double precision, asi que tambien valen los decimales: make_timestamp(2024, 3, 15, 14, 30, 7.5). Hay parientes cercanos: make_date(2024, 3, 15) para una fecha pura y make_time(14, 30, 0) para una hora del dia.

Comparalo con la concatenacion habitual de cadenas, fragil y dependiente de la sesion:

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

Si m es 3 y no 03, o DateStyle esta en DMY, ese codigo devuelve en silencio la fecha equivocada o falla. make_timestamp elimina ambos fallos de una vez.

Un intervalo a partir de argumentos con nombre

make_interval construye un interval con campos con nombre: years, months, weeks, days, hours, mins, secs. Pasa solo lo que necesites; el resto vale cero por defecto.

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

La gran ventaja es la parametrizacion. Cuando la cantidad es un numero variable, no puedes meterla en un literal INTERVAL de cadena, pero si pasarla directo a 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';

Ese 14 podria ser una columna o un marcador $1. Esta es la diferencia clave con un intervalo de cadena: INTERVAL '$1 days' no funciona porque el marcador quedaria dentro del literal, mientras que make_interval(days => $1) se enlaza correctamente.

-- 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 y la zona horaria

make_timestamp tiene un hermano con zona, make_timestamptz. Un argumento de texto extra nombra la zona en la que se interpretan los numeros entregados; el resultado es un timestamptz.

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

Sin el ultimo argumento los numeros se leen en la zona de la sesion actual (TimeZone). Es comodo para fechas limite ancladas a una region concreta:

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

Cuidado: los argumentos de make_* no se desbordan hacia adelante. make_timestamp(2024, 13, 1, 0, 0, 0) no pasa a enero de 2025 — lanza field value out of range. Lo mismo con make_date(2024, 2, 30). Si las entradas son numeros no confiables, validalas antes o captura la excepcion.

Diferencias en otros motores

make_timestamp, make_interval y compania son de PostgreSQL. Otros motores siguen otro camino:

  • MySQL: arma la fecha con MAKEDATE/MAKETIME o STR_TO_DATE('2024-03-15','%Y-%m-%d'). Los intervalos usan la sintaxis INTERVAL 10 DAY, y para una cantidad variable escribes INTERVAL n DAY, donde n puede ser una expresion.
  • ClickHouse: usa makeDateTime(2024, 3, 15, 14, 30, 0) y makeDateTime64(...) para precision de fraccion de segundo; la zona es un argumento aparte. Construye un intervalo con toIntervalDay(n), toIntervalHour(n) y sumalos.

Si el codigo debe ser portable, aisla el armado de fechas en una sola capa: la familia make_* en PostgreSQL, funciones nativas en el resto. El principio central es el mismo en todas partes: no pegues fechas desde cadenas cuando el motor sabe construirlas desde numeros.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador