sqlpostgresqldate-partextract

DATE_PART no SQL: partes numericas da data, dia da semana e campo dinamico

Como o DATE_PART retorna uma parte numerica da data, como difere do EXTRACT e por que dow numera o domingo como 0.

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

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;
-- 14 | 3 | 168 | 25

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.

DATE_PART versus EXTRACT

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.

-- 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+, 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,     -- domingo -> 0
  DATE_PART('isodow', DATE '2026-06-21') AS isodow;  -- domingo -> 7

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.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador