sqlpostgresqldate-partextract

DATE_PART en SQL: partes numericas de fecha, dia de la semana y campo dinamico

Como DATE_PART devuelve una parte numerica de la fecha, en que se diferencia de EXTRACT y por que dow numera el domingo como 0.

3 min de lecturaReferencesql · postgresql · date-part · extract · date-functions · mysql

DATE_PART extrae un unico campo numerico de una marca de tiempo: la hora, el dia de la semana, el numero de semana, los segundos desde la epoca. Es la forma de funcion del operador EXTRACT, pero aqui el campo es una cadena simple, lo que permite pasarlo de forma dinamica.

Que devuelve DATE_PART

El primer argumento es el nombre del campo como cadena ('hour', 'dow', 'doy', 'week', 'month', 'epoch', etc.); el segundo es un timestamp o una date. El resultado siempre es double precision, un numero, no un intervalo ni una cadena.

SELECT
  DATE_PART('hour',  TIMESTAMP '2026-06-17 14:32:09') AS hour,
  DATE_PART('dow',   TIMESTAMP '2026-06-17 14:32:09') AS day_of_week,
  DATE_PART('doy',   TIMESTAMP '2026-06-17 14:32:09') AS day_of_year,
  DATE_PART('week',  TIMESTAMP '2026-06-17 14:32:09') AS iso_week;
-- 14 | 3 | 168 | 25

Campos utiles:

  • 'hour', 'minute', 'second' son componentes de hora; 'second' incluye la parte fraccionaria.
  • 'year', 'month', 'day' son componentes de fecha.
  • 'dow' es el dia de la semana, 0 = domingo ... 6 = sabado.
  • 'doy' es el dia del ano, de 1 a 366.
  • 'week' es el numero de semana ISO 8601.
  • 'epoch' es el numero de segundos desde 1970-01-01 00:00:00 UTC.

DATE_PART frente a EXTRACT

EXTRACT('hour' FROM ts) y DATE_PART('hour', ts) producen el mismo numero. La diferencia es sintactica: EXTRACT es un operador con la palabra FROM, mientras que DATE_PART es una funcion ordinaria.

-- Estas dos lineas son equivalentes
SELECT EXTRACT(dow FROM created_at) FROM orders;
SELECT DATE_PART('dow', created_at) FROM orders;

La ventaja practica de la funcion es que el campo es un literal de cadena, asi que es facil pasarlo como parametro. Puedes agrupar pedidos por cualquier campo de fecha sin reescribir la consulta:

SELECT
  DATE_PART('hour', created_at) AS hour_of_day,
  COUNT(*)                      AS orders
FROM orders
WHERE status = 'paid'
GROUP BY DATE_PART('hour', created_at)
ORDER BY hour_of_day;

En PostgreSQL 14+, EXTRACT devuelve numeric mientras que DATE_PART sigue devolviendo double precision; para comparaciones y ROUND esa distincion a veces importa.

Dia de la semana: dow frente a isodow

La mayor fuente de confusion es la numeracion de los dias. 'dow' empieza la semana el domingo y lo numera como cero; 'isodow' sigue ISO, donde el lunes es 1 y el domingo es 7.

SELECT
  DATE_PART('dow',    DATE '2026-06-21') AS dow,     -- domingo -> 0
  DATE_PART('isodow', DATE '2026-06-21') AS isodow;  -- domingo -> 7

Un informe tipico de "actividad por dia de la semana" con una etiqueta legible:

SELECT
  DATE_PART('isodow', created_at) AS weekday_num,
  TO_CHAR(created_at, 'Dy')       AS weekday,
  COUNT(*)                        AS signups
FROM users
GROUP BY DATE_PART('isodow', created_at), TO_CHAR(created_at, 'Dy')
ORDER BY weekday_num;

Trampa: si filtras fines de semana con DATE_PART('dow', d) IN (0, 6) y luego cambias a isodow, el sabado y el domingo pasan a ser 6 y 7, asi que IN (0, 6) empieza a descartar el domingo en silencio. Fija siempre que campo estas usando.

Epoca y diferencias de tiempo

El campo 'epoch' convierte una marca de tiempo en segundos, y de un intervalo extrae su duracion completa en segundos. Es una forma comoda de calcular una antiguedad o una duracion como un solo numero.

SELECT
  id,
  DATE_PART('epoch', NOW() - created_at) / 86400 AS account_age_days
FROM users
ORDER BY account_age_days DESC
LIMIT 10;

La misma idea para la metrica de negocio "antiguedad media del pedido en horas" agrupada por departamento del empleado:

SELECT
  e.dept,
  AVG(DATE_PART('epoch', NOW() - o.created_at) / 3600) AS avg_order_age_hours
FROM orders o
JOIN users u    ON u.id = o.user_id
JOIN employees e ON e.name = u.name
GROUP BY e.dept;

Recuerda: DATE_PART('epoch', interval) devuelve los segundos completos de un intervalo de mas de un dia, no una "parte de un dia", a diferencia de 'hour', que en un intervalo devuelve solo el componente de hora.

Diferencias en MySQL y ClickHouse

El nombre DATE_PART no es universal.

  • MySQL no tiene DATE_PART. Usa EXTRACT(HOUR FROM ts) o las funciones dedicadas HOUR(), DAYOFWEEK() (donde el domingo es 1), DAYOFYEAR(), WEEK().
SELECT
  HOUR(created_at)      AS hour_of_day,
  DAYOFWEEK(created_at) AS dow_sun_is_1,
  COUNT(*)              AS orders
FROM orders
GROUP BY HOUR(created_at), DAYOFWEEK(created_at);
  • ClickHouse ofrece toHour, toDayOfWeek (el lunes es 1), toDayOfYear y toUnixTimestamp para la epoca.
SELECT
  toHour(created_at)      AS hour_of_day,
  toDayOfWeek(created_at) AS dow_mon_is_1,
  count()                 AS orders
FROM orders
GROUP BY hour_of_day, dow_mon_is_1;

La intencion es identica en todas partes, sacar un numero de una fecha, pero cada base de datos numera el dia de la semana a su manera, y eso es lo primero que conviene revisar al portar una consulta.

Practica con ejercicios reales

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

Abrir el entrenador