DATE_PART extrai um unico campo numerico de um timestamp: a hora, o dia da semana, o numero da semana, os segundos desde a epoca. E a forma de funcao do operador EXTRACT, mas aqui o campo e uma string simples, o que permite passa-lo de forma dinamica.
O que o DATE_PART retorna
O primeiro argumento e o nome do campo como string ('hour', 'dow', 'doy', 'week', 'month', 'epoch', etc.); o segundo e um timestamp ou uma date. O resultado e sempre double precision, um numero, nao um intervalo nem uma string.
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 uteis:
'hour', 'minute', 'second' sao componentes de hora; 'second' inclui a parte fracionaria.
'year', 'month', 'day' sao componentes de data.
'dow' e o dia da semana, 0 = domingo ... 6 = sabado.
'doy' e o dia do ano, de 1 a 366.
'week' e o numero da semana ISO 8601.
'epoch' e o numero de segundos desde 1970-01-01 00:00:00 UTC.
EXTRACT('hour' FROM ts) e DATE_PART('hour', ts) produzem o mesmo numero. A diferenca e sintatica: EXTRACT e um operador com a palavra FROM, enquanto DATE_PART e uma funcao comum.
SELECT EXTRACT(dow FROM created_at) FROM orders;
SELECT DATE_PART('dow', created_at) FROM orders;
A vantagem pratica da funcao e que o campo e um literal de string, entao e facil passa-lo como parametro. Voce pode agrupar pedidos por qualquer campo de data sem reescrever a 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;
No PostgreSQL 14+, EXTRACT retorna numeric enquanto DATE_PART ainda retorna double precision; para comparacoes e ROUND essa distincao as vezes importa.
Dia da semana: dow versus isodow
A maior fonte de confusao e a numeracao dos dias. 'dow' comeca a semana no domingo e o numera como zero; 'isodow' segue o ISO, onde a segunda-feira e 1 e o domingo e 7.
SELECT
DATE_PART('dow', DATE '2026-06-21') AS dow,
DATE_PART('isodow', DATE '2026-06-21') AS isodow;
Um relatorio tipico de "atividade por dia da semana" com um rotulo legivel:
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;
Pegadinha: se voce filtrar finais de semana com DATE_PART('dow', d) IN (0, 6) e depois mudar para isodow, sabado e domingo viram 6 e 7, entao IN (0, 6) passa a descartar o domingo em silencio. Sempre fixe qual campo voce esta usando.
Epoca e diferencas de tempo
O campo 'epoch' transforma um timestamp em segundos, e de um intervalo extrai sua duracao completa em segundos. E uma forma pratica de calcular uma idade ou uma duracao como um unico numero.
SELECT
id,
DATE_PART('epoch', NOW() - created_at) / 86400 AS account_age_days
FROM users
ORDER BY account_age_days DESC
LIMIT 10;
A mesma ideia para a metrica de negocio "idade media do pedido em horas" agrupada por departamento do funcionario:
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;
Lembre-se: DATE_PART('epoch', interval) retorna os segundos completos de um intervalo maior que um dia, nao uma "parte de um dia", ao contrario de 'hour', que em um intervalo retorna apenas o componente de hora.
Diferencas no MySQL e ClickHouse
O nome DATE_PART nao e universal.
- MySQL nao tem
DATE_PART. Use EXTRACT(HOUR FROM ts) ou as funcoes dedicadas HOUR(), DAYOFWEEK() (onde o domingo e 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 oferece
toHour, toDayOfWeek (a segunda-feira e 1), toDayOfYear e toUnixTimestamp para a 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;
A intencao e identica em todo lugar, extrair um numero de uma data, mas cada banco numera o dia da semana a sua maneira, e isso e a primeira coisa a verificar ao portar uma consulta.
DATE_PARTextrai um unico campo numerico de um timestamp: a hora, o dia da semana, o numero da semana, os segundos desde a epoca. E a forma de funcao do operadorEXTRACT, mas aqui o campo e uma string simples, o que permite passa-lo de forma dinamica.O que o DATE_PART retorna
O primeiro argumento e o nome do campo como string (
'hour','dow','doy','week','month','epoch', etc.); o segundo e umtimestampou umadate. O resultado e sempredouble precision, um numero, nao um intervalo nem uma string.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 uteis:
'hour','minute','second'sao componentes de hora;'second'inclui a parte fracionaria.'year','month','day'sao componentes de data.'dow'e o dia da semana,0= domingo ...6= sabado.'doy'e o dia do ano, de1a366.'week'e o numero da semana ISO 8601.'epoch'e o numero de segundos desde1970-01-01 00:00:00 UTC.DATE_PART versus EXTRACT
EXTRACT('hour' FROM ts)eDATE_PART('hour', ts)produzem o mesmo numero. A diferenca e sintatica:EXTRACTe um operador com a palavraFROM, enquantoDATE_PARTe uma funcao comum.-- Estas duas linhas sao equivalentes SELECT EXTRACT(dow FROM created_at) FROM orders; SELECT DATE_PART('dow', created_at) FROM orders;A vantagem pratica da funcao e que o campo e um literal de string, entao e facil passa-lo como parametro. Voce pode agrupar pedidos por qualquer campo de data sem reescrever a 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;No PostgreSQL 14+,
EXTRACTretornanumericenquantoDATE_PARTainda retornadouble precision; para comparacoes eROUNDessa distincao as vezes importa.Dia da semana: dow versus isodow
A maior fonte de confusao e a numeracao dos dias.
'dow'comeca a semana no domingo e o numera como zero;'isodow'segue o ISO, onde a segunda-feira e1e o domingo e7.SELECT DATE_PART('dow', DATE '2026-06-21') AS dow, -- domingo -> 0 DATE_PART('isodow', DATE '2026-06-21') AS isodow; -- domingo -> 7Um relatorio tipico de "atividade por dia da semana" com um rotulo legivel:
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;Pegadinha: se voce filtrar finais de semana com
DATE_PART('dow', d) IN (0, 6)e depois mudar paraisodow, sabado e domingo viram6e7, entaoIN (0, 6)passa a descartar o domingo em silencio. Sempre fixe qual campo voce esta usando.Epoca e diferencas de tempo
O campo
'epoch'transforma um timestamp em segundos, e de um intervalo extrai sua duracao completa em segundos. E uma forma pratica de calcular uma idade ou uma duracao como um unico numero.SELECT id, DATE_PART('epoch', NOW() - created_at) / 86400 AS account_age_days FROM users ORDER BY account_age_days DESC LIMIT 10;A mesma ideia para a metrica de negocio "idade media do pedido em horas" agrupada por departamento do funcionario:
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;Lembre-se:
DATE_PART('epoch', interval)retorna os segundos completos de um intervalo maior que um dia, nao uma "parte de um dia", ao contrario de'hour', que em um intervalo retorna apenas o componente de hora.Diferencas no MySQL e ClickHouse
O nome
DATE_PARTnao e universal.DATE_PART. UseEXTRACT(HOUR FROM ts)ou as funcoes dedicadasHOUR(),DAYOFWEEK()(onde o domingo e1),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(a segunda-feira e1),toDayOfYearetoUnixTimestamppara a 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;A intencao e identica em todo lugar, extrair um numero de uma data, mas cada banco numera o dia da semana a sua maneira, e isso e a primeira coisa a verificar ao portar uma consulta.