sqlpostgresqldatestime

CURRENT_DATE y CURRENT_TIME en SQL: la fecha de hoy y la hora actual

CURRENT_DATE y CURRENT_TIME son valores especiales de SQL sin parentesis: la fecha de hoy y la hora con su zona.

3 min de lecturaReferencesql · postgresql · dates · time · current-date

En SQL, CURRENT_DATE y CURRENT_TIME no son funciones sino valores especiales: devuelven la fecha de hoy y la hora actual del dia sin un solo parentesis. Parece una nimiedad, pero precisamente la ausencia de () y el tipo del resultado son lo que mas confunde.

Valores especiales, sin parentesis

El estandar SQL define un punado de "registros especiales": CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP. Se escriben como palabra clave desnuda — nunca CURRENT_DATE().

SELECT CURRENT_DATE, CURRENT_TIME;
-- 2026-06-17 | 18:42:07.512+02
  • CURRENT_DATE produce un date — solo ano, mes y dia.
  • CURRENT_TIME produce time with time zone (timetz en corto) — una hora del dia mas un desfase de zona.
  • CURRENT_TIMESTAMP combina ambos: fecha y hora completas con zona (timestamptz).

Todos leen el instante en que empezo la transaccion, no el instante en que se ejecuta la fila. Dentro de una misma transaccion CURRENT_DATE no "saltara" la medianoche entre consultas — eso es comportamiento del estandar, no un fallo.

Hoy en WHERE y en informes

El uso mas habitual es seleccionar las filas de hoy. Puedes comparar created_at (un timestamptz) directamente con CURRENT_DATE, pero cuidado con los limites: mejor un rango semiabierto [hoy, manana).

SELECT id, email, created_at
FROM users
WHERE created_at >= CURRENT_DATE
  AND created_at <  CURRENT_DATE + INTERVAL '1 day';

Pedidos de los ultimos 30 dias — la aritmetica sobre CURRENT_DATE se lee limpia, sin conversiones:

SELECT id, user_id, amount, status
FROM orders
WHERE status = 'paid'
  AND created_at >= CURRENT_DATE - INTERVAL '30 days';

Cuidado: no escribas DATE(created_at) = CURRENT_DATE sobre un conjunto grande. Envolver la columna en DATE(...) anula cualquier indice sobre created_at — el planificador no puede usarlo y cae en un seq scan. El rango >= ... AND < ... mantiene el indice en juego.

CURRENT_DATE como DEFAULT

CURRENT_DATE es un valor por defecto perfecto para una columna de fecha: se evalua en cada insercion.

CREATE TABLE signups (
  user_id   bigint PRIMARY KEY,
  signed_on date NOT NULL DEFAULT CURRENT_DATE
);

INSERT INTO signups (user_id) VALUES (101);
-- signed_on = today, filled automatically

Para campos de "creado el" sueles recurrir mejor a CURRENT_TIMESTAMP (o now()), para conservar tambien la hora y la zona:

ALTER TABLE orders
  ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP;

La diferencia clave: CURRENT_DATE guarda solo el dia y descarta la hora, mientras que CURRENT_TIMESTAMP conserva el instante completo. Elige el tipo de columna a conciencia — date frente a timestamptz.

CURRENT_TIME frente a un timestamp completo

CURRENT_TIME es la hora del dia, sin fecha asociada. El tipo timetz lleva un desfase de zona pero no una fecha, y ahi es justo donde se vuelve propenso a errores.

SELECT CURRENT_TIME            AS clock,        -- 18:42:07.512+02  (timetz)
       CURRENT_TIMESTAMP       AS full_moment,  -- 2026-06-17 18:42:07.512+02
       CURRENT_TIMESTAMP::time AS local_clock;  -- 18:42:07.512     (plain time)
  • No puedes restar de forma fiable un timetz de otro cruzando una frontera de zona — sin fecha, pasar la medianoche es ambiguo.
  • Para la logica de "horario laboral" sueles tomar CURRENT_TIMESTAMP::time (un time sin zona), no CURRENT_TIME.
  • Cuando necesitas fecha y hora, la respuesta correcta casi siempre es CURRENT_TIMESTAMP, no un par CURRENT_DATE + CURRENT_TIME.

Ejemplo: cuenta un pedido como diurno si se creo entre las 09:00 y las 18:00 hora local.

SELECT id, amount
FROM orders
WHERE created_at::time BETWEEN TIME '09:00' AND TIME '18:00';

Diferencias entre motores

  • PostgreSQL: totalmente estandar. CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP no llevan parentesis; now() es sinonimo de CURRENT_TIMESTAMP.
  • MySQL: CURRENT_DATE y CURDATE() son equivalentes, igual que CURRENT_TIME y CURTIME(). El tipo TIME de MySQL no guarda zona, asi que aqui no existe timetz.
  • ClickHouse: ofrece today() y now(); CURRENT_TIMESTAMP se admite como alias, pero no hay un tipo independiente de "hora del dia con zona".

Si el codigo debe ser portable, quedate con CURRENT_DATE/CURRENT_TIMESTAMP sin parentesis — la forma mas entendida — y no te apoyes en la semantica de timetz fuera de PostgreSQL.

Practica con ejercicios reales

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

Abrir el entrenador