sqlpostgresqldatestime

CURRENT_DATE, CURRENT_TIME и CURRENT_TIMESTAMP в SQL

CURRENT_DATE, CURRENT_TIME и CURRENT_TIMESTAMP — значения SQL без скобок: дата, время суток с поясом и полный момент. Разбираем типы, фильтры WHERE и DEFAULT.

4 мин чтенияСправочникsql · postgresql · dates · time · current-date

В SQL CURRENT_DATE и CURRENT_TIME — это не функции, а специальные значения: они возвращают сегодняшнюю дату и текущее время суток без единой скобки. Звучит как мелочь, но именно отсутствие () и тип результата каждый раз сбивают людей с толку.

Чаще всего эти значения встречаются в трёх местах: в фильтре WHERE («строки за сегодня», «за последние 30 дней»), в DEFAULT для колонок с датой создания и в выражениях, где нужен текущий момент времени. Главная развилка — какой из трёх вариантов брать. CURRENT_DATE даёт только дату (date), CURRENT_TIME — только время суток с поясом (timetz), а CURRENT_TIMESTAMP — полный момент (timestamptz). Перепутать их легко, и тогда фильтр по дню молча сравнивает date с timestamptz, а DEFAULT теряет время суток. К тому же все три значения вычисляются один раз на транзакцию, а не на каждую строку, поэтому в массовой вставке у всех строк будет одна и та же отметка времени. Ниже разберём каждое из трёх значений, его тип и типичные ловушки на границах суток и часового пояса.

Специальные значения без скобок

Стандарт SQL определяет горстку «специальных регистров»: CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP. Их пишут голым ключевым словом — никаких CURRENT_DATE().

SELECT CURRENT_DATE, CURRENT_TIME;
-- 2026-06-17 | 18:42:07.512+02
  • CURRENT_DATE даёт значение типа date — только год, месяц и день.
  • CURRENT_TIME даёт time with time zone (сокращённо timetz) — время суток плюс смещение пояса.
  • CURRENT_TIMESTAMP объединяет оба: полная дата и время с поясом (timestamptz).

Все они берут момент начала транзакции, а не момент исполнения строки. Внутри одной транзакции CURRENT_DATE не «перепрыгнет» полночь между запросами — это поведение по стандарту, а не баг.

Сегодня в WHERE и в отчётах

Самое частое применение — отобрать строки за сегодня. Сравнивать created_at (это timestamptz) напрямую с CURRENT_DATE можно, но аккуратно с границами: лучше брать полуинтервал «сегодня включительно, завтра уже нет».

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

Заказы за последние 30 дней — арифметика с CURRENT_DATE читается без приведений типов:

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

Ловушка: не пишите DATE(created_at) = CURRENT_DATE в большом наборе. Обёртка DATE(...) вокруг столбца убивает индекс по created_at — планировщик не сможет использовать его и пойдёт в seq scan. Диапазон >= ... AND < ... сохраняет индекс.

CURRENT_DATE как DEFAULT

CURRENT_DATE идеально подходит на роль значения по умолчанию для колонки-даты: оно вычисляется при каждой вставке.

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

Для полей «когда создано» чаще берут CURRENT_TIMESTAMP (или now()), чтобы сохранить и время с поясом:

ALTER TABLE orders
  ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP;

Ключевая разница: CURRENT_DATE хранит только сутки и теряет время дня, а CURRENT_TIMESTAMP сохраняет полный момент. Выбирайте тип колонки осознанно — date против timestamptz.

CURRENT_TIME против полного timestamp

CURRENT_TIME — это именно время суток, без даты. Тип timetz несёт смещение пояса, но не несёт самой даты, и из-за этого с ним легко наделать ошибок.

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)
  • Нельзя надёжно вычесть один timetz из другого через границу пояса — без даты переход через полночь неоднозначен.
  • Для бизнес-логики «рабочие часы» обычно берут CURRENT_TIMESTAMP::time (тип time без пояса), а не CURRENT_TIME.
  • Если нужна и дата, и время — почти всегда правильный ответ это CURRENT_TIMESTAMP, а не пара CURRENT_DATE + CURRENT_TIME.

Пример: смена считается дневной, если заказ создан между 09:00 и 18:00 по локальному времени.

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

Различия в других СУБД

  • PostgreSQL: всё по стандарту. CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP — без скобок; now() — синоним CURRENT_TIMESTAMP.
  • MySQL: CURRENT_DATE и CURDATE() эквивалентны, CURRENT_TIME и CURTIME() тоже. Тип TIME в MySQL не хранит пояс, так что timetz тут просто нет.
  • ClickHouse: есть today() и now(); CURRENT_TIMESTAMP поддержан как алиас, а отдельного «времени суток с поясом» как самостоятельного типа нет.

Главный источник ошибок с CURRENT_DATE и CURRENT_TIMESTAMP — не сам синтаксис, а часовой пояс и границы суток. Все эти значения берут момент начала транзакции, поэтому в одной длинной транзакции, начатой в 23:59, CURRENT_DATE так и останется «вчерашним», даже если строки вставляются уже после полуночи. А значение CURRENT_DATE зависит от пояса сессии: при SET timezone тот же абсолютный момент может попасть в соседние сутки, и фильтр «за сегодня» сдвинется на день. Поэтому для отчётов по дню стоит явно фиксировать пояс — например, сравнивать created_at AT TIME ZONE 'UTC' с границами, посчитанными в том же поясе, а не полагаться на пояс по умолчанию.

Отдельная ловушка — CURRENT_TIME и его тип timetz. Вычитать одно значение timetz из другого через полночь бессмысленно: без даты непонятно, прошли сутки или нет, а смещение пояса в timetz ещё и не учитывает переход на летнее время. Поэтому в PostgreSQL тип timetz считается скорее наследием, чем рабочим инструментом, и в схемах его почти не держат. Если нужно сравнивать время суток (рабочие часы, окна обслуживания), почти всегда правильнее взять CURRENT_TIMESTAMP::time — чистый time без пояса — и держать дату отдельно в CURRENT_DATE или прямо в CURRENT_TIMESTAMP. А если важен сам факт «когда это произошло», храните CURRENT_TIMESTAMP целиком и режьте его на дату и время уже в запросе.

Если код должен быть переносимым, держитесь CURRENT_DATE/CURRENT_TIMESTAMP без скобок — это самый широко понятый вариант — и не полагайтесь на семантику timetz за пределами PostgreSQL.

Закрепи на практике

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр