sqlpostgresqldatestime

CURRENT_DATE e CURRENT_TIME no SQL: a data de hoje e a hora atual

CURRENT_DATE e CURRENT_TIME sao valores especiais do SQL sem parenteses: a data de hoje e a hora com fuso.

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

No SQL, CURRENT_DATE e CURRENT_TIME nao sao funcoes, e sim valores especiais: devolvem a data de hoje e a hora atual do dia sem um unico parenteses. Parece detalhe, mas e justamente a ausencia de () e o tipo do resultado que mais confundem as pessoas.

Valores especiais, sem parenteses

O padrao SQL define um punhado de "registradores especiais": CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP. Eles se escrevem como palavra-chave nua — nunca CURRENT_DATE().

SELECT CURRENT_DATE, CURRENT_TIME;
-- 2026-06-17 | 18:42:07.512+02
  • CURRENT_DATE produz um date — apenas ano, mes e dia.
  • CURRENT_TIME produz time with time zone (timetz, abreviado) — uma hora do dia mais o deslocamento de fuso.
  • CURRENT_TIMESTAMP combina os dois: data e hora completas com fuso (timestamptz).

Todos leem o instante em que a transacao comecou, e nao o instante em que a linha executa. Dentro de uma mesma transacao o CURRENT_DATE nao vai "pular" a meia-noite entre consultas — isso e comportamento do padrao, nao um bug.

Hoje no WHERE e em relatorios

O uso mais comum e selecionar as linhas de hoje. Voce pode comparar created_at (um timestamptz) direto com CURRENT_DATE, mas atencao aos limites: prefira um intervalo semiaberto [hoje, amanha).

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

Pedidos dos ultimos 30 dias — a aritmetica sobre CURRENT_DATE fica limpa, sem conversoes:

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

Pegadinha: nao escreva DATE(created_at) = CURRENT_DATE sobre um conjunto grande. Envolver a coluna em DATE(...) mata qualquer indice sobre created_at — o planejador nao consegue usa-lo e cai num seq scan. O intervalo >= ... AND < ... mantem o indice em jogo.

CURRENT_DATE como DEFAULT

CURRENT_DATE e um valor padrao perfeito para uma coluna de data: ele e avaliado a cada insercao.

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 "criado em" voce geralmente prefere CURRENT_TIMESTAMP (ou now()), para guardar tambem a hora e o fuso:

ALTER TABLE orders
  ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP;

A diferenca chave: CURRENT_DATE guarda apenas o dia e descarta a hora, enquanto CURRENT_TIMESTAMP preserva o instante completo. Escolha o tipo da coluna com criterio — date contra timestamptz.

CURRENT_TIME contra um timestamp completo

CURRENT_TIME e a hora do dia, sem data associada. O tipo timetz carrega um deslocamento de fuso, mas nao uma data, e e ai que ele fica propenso a erro.

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)
  • Voce nao consegue subtrair de forma confiavel um timetz de outro cruzando uma fronteira de fuso — sem data, atravessar a meia-noite e ambiguo.
  • Para a logica de "horario comercial" voce normalmente usa CURRENT_TIMESTAMP::time (um time sem fuso), e nao CURRENT_TIME.
  • Quando precisa de data e hora, a resposta certa quase sempre e CURRENT_TIMESTAMP, e nao um par CURRENT_DATE + CURRENT_TIME.

Exemplo: conte um pedido como diurno se ele foi criado entre 09:00 e 18:00 no horario local.

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

Diferencas entre bancos

  • PostgreSQL: totalmente padrao. CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP nao levam parenteses; now() e sinonimo de CURRENT_TIMESTAMP.
  • MySQL: CURRENT_DATE e CURDATE() sao equivalentes, assim como CURRENT_TIME e CURTIME(). O tipo TIME do MySQL nao guarda fuso, entao aqui nao existe timetz.
  • ClickHouse: oferece today() e now(); CURRENT_TIMESTAMP e aceito como alias, mas nao ha um tipo proprio de "hora do dia com fuso".

Se o codigo precisa ser portavel, fique com CURRENT_DATE/CURRENT_TIMESTAMP sem parenteses — a forma mais compreendida — e nao dependa da semantica de timetz fora do PostgreSQL.

Pratique com exercícios reais

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

Abrir o treinador