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;
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.
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.
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,
DATE_PART('isodow', DATE '2026-06-21') AS isodow;
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.
DATE_PARTextrae 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 operadorEXTRACT, 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 untimestampo unadate. El resultado siempre esdouble 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 | 25Campos 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, de1a366.'week'es el numero de semana ISO 8601.'epoch'es el numero de segundos desde1970-01-01 00:00:00 UTC.DATE_PART frente a EXTRACT
EXTRACT('hour' FROM ts)yDATE_PART('hour', ts)producen el mismo numero. La diferencia es sintactica:EXTRACTes un operador con la palabraFROM, mientras queDATE_PARTes 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+,
EXTRACTdevuelvenumericmientras queDATE_PARTsigue devolviendodouble precision; para comparaciones yROUNDesa 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 es1y el domingo es7.SELECT DATE_PART('dow', DATE '2026-06-21') AS dow, -- domingo -> 0 DATE_PART('isodow', DATE '2026-06-21') AS isodow; -- domingo -> 7Un 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 aisodow, el sabado y el domingo pasan a ser6y7, asi queIN (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_PARTno es universal.DATE_PART. UsaEXTRACT(HOUR FROM ts)o las funciones dedicadasHOUR(),DAYOFWEEK()(donde el domingo es1),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);toHour,toDayOfWeek(el lunes es1),toDayOfYearytoUnixTimestamppara 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.