CodeRang
Темы SQL

Дата в SQL: функции и работа с датами

Дата в SQL требует учитывать тип данных, границы периода и часовой пояс. Разберём работу с датами в SQL: формат даты, извлечение года, текущую дату, разницу дат и группировку по календарным периодам.

Обновлено · Команда SQL Arena

Что потренируете

  • Группировать даты по неделям и месяцам через DATE_TRUNC
  • Извлекать год, месяц и другие части даты через EXTRACT
  • Задавать интервалы времени с помощью INTERVAL
  • Фильтровать периоды полуоткрытыми интервалами
  • Учитывать часовые пояса при работе с timestamptz

Пример задачи в тренажёре

Так выглядит задача в SQL Arena: условие, редактор, результат и схема базы.

Пред.След.Случайная
ЗаданиеОтправкиAI Mentor
Посчитать события по месяцам в часовом поясе Берлина

В таблице events хранятся события аккаунтов и время их начала в timestamptz. Нужно взять события с марта по май 2026 года по локальному времени Берлина и вернуть начало месяца в month_start, количество событий в event_count и число аккаунтов с событиями в accounts. Июнь в диапазон не входит. Итог нужно отсортировать по месяцу.

Запрос 1PostgreSQLv16
SELECT
  DATE_TRUNC('month', starts_at AT TIME ZONE 'Europe/Berlin')::date AS month_start,
  COUNT(*) AS event_count,
  COUNT(DISTINCT account_id) AS accounts
FROM events
WHERE starts_at >= TIMESTAMPTZ '2026-03-01 00:00:00 Europe/Berlin'
  AND starts_at < TIMESTAMPTZ '2026-06-01 00:00:00 Europe/Berlin'
GROUP BY 1
ORDER BY 1;
Отправить
Результатaccountsevents
Ответ принят

Работа с датами в SQL на примере запроса

Фильтр начинается не с DATE_TRUNC, а с точных границ периода. Условие берёт всё от начала 1 марта включительно и до начала 1 июня исключительно. Такая запись называется полуоткрытым интервалом: начало входит, конец нет. Она удобнее конструкции с последним днём месяца, потому что не требует угадывать 23:59:59 и не ломается на значениях с долями секунды. Для следующего месяца достаточно использовать его первую границу.

Поле starts_at имеет тип timestamptz, поэтому перед определением календарного месяца важно решить, в каком часовом поясе считать дату. Выражение starts_at AT TIME ZONE 'Europe/Berlin' переводит момент времени в локальные дату и время Берлина, а DATE_TRUNC('month', ...) отбрасывает день и время до первого числа месяца. Приведение к date оставляет в результате только календарную дату. Благодаря этому событие около полуночи относится к тому месяцу, который видит пользователь в выбранной зоне.

После преобразования GROUP BY собирает события в три месячные группы, COUNT(*) считает строки, а COUNT(DISTINCT account_id) — разные аккаунты. Для задач другого типа пригодится EXTRACT: например, EXTRACT(MONTH FROM starts_at) возвращает номер месяца, а EXTRACT(DOW FROM ...) — день недели. INTERVAL удобен, когда граница строится относительно другой даты: current_date - INTERVAL '30 days' или month_start + INTERVAL '1 month'. Но для фиксированного диапазона явные границы обычно легче проверить.

Набор функций для дат зависит от диалекта SQL. Год из даты можно получать через EXTRACT(YEAR FROM date_value) в системах, которые поддерживают этот синтаксис. Текущая дата часто доступна через CURRENT_DATE. Для разницы дат одни СУБД используют специальные функции вроде DATEDIFF, а другие — вычитание дат или работу с интервалами. Форматирование даты тоже различается по диалектам и не следует путать с её хранением: DATE и TIMESTAMP остаются типами данных независимо от того, как значение показано пользователю. При фильтрации периодов удобно использовать полуоткрытые интервалы: >= начала и < следующей границы.

SQLPostgreSQL v16
SELECT
  DATE_TRUNC('month', starts_at AT TIME ZONE 'Europe/Berlin')::date AS month_start,
  COUNT(*) AS event_count,
  COUNT(DISTINCT account_id) AS accounts
FROM events
WHERE starts_at >= TIMESTAMPTZ '2026-03-01 00:00:00 Europe/Berlin'
  AND starts_at < TIMESTAMPTZ '2026-06-01 00:00:00 Europe/Berlin'
GROUP BY 1
ORDER BY 1;
Результат запроса
month_startevent_countaccounts
2026-03-0122
2026-04-0133
2026-05-0122

Ошибки при работе с датой и временем в SQL

01

BETWEEN для диапазона месяцев

Запись BETWEEN '2026-03-01' AND '2026-05-31' выглядит естественно, но верхняя граница превращается в начало 31 мая и может исключить события позже полуночи. Надёжнее писать start >= нижняя_граница AND start < следующая_граница. Этот шаблон одинаково работает для дней, месяцев и лет.

02

DATE_TRUNC до перевода часового пояса

Если сначала определить месяц в одной временной зоне, а потом показать время в другой, события около полуночи могут оказаться в неправильной группе. Для timestamptz сначала определяют бизнес-зону, затем получают локальную дату или начало периода.

03

EXTRACT(MONTH) без года

Группировка только по номеру месяца объединит январь 2025 и январь 2026. Если данные охватывают несколько лет, группируйте по DATE_TRUNC('month', date_column) либо добавляйте в ключ и год через EXTRACT(YEAR FROM ...).

Задачи по теме в тренажёре

Трек «SQL с нуля → Аналитик»

После такого примера полезно решить несколько задач с разными видами временных условий. В бесплатных Easy-задачах можно потренироваться находить пациентов, родившихся в мае, удалять устаревшие строки аудит-лога, выбирать последний вход пользователя за конкретный год и находить сессии, которые остаются открытыми дольше суток. Дальше встречаются задачи на временные окна и расходы за месяц или год. Если базовые фильтры уже получаются уверенно, следующий логичный маршрут — трек «SQL с нуля → Аналитик»: там работа с датами встречается вместе с другими приёмами, которые нужны в аналитических запросах.

Частые вопросы

Как хранится дата в SQL?

Для календарной даты обычно используют тип DATE, а для даты со временем — типы семейства TIMESTAMP. Конкретные типы и поддержка часовых поясов зависят от СУБД.

Как изменить формат даты в SQL?

Способ форматирования зависит от диалекта SQL и обычно выполняется специальной функцией преобразования даты в строку. Форматирование меняет представление значения, а не сам тип хранимой даты.

Как получить год из даты в SQL?

Во многих SQL-диалектах год можно получить выражением EXTRACT(YEAR FROM date_value). В некоторых СУБД также доступны отдельные функции для извлечения года.

Как получить текущую дату в SQL?

Стандартное выражение CURRENT_DATE возвращает текущую календарную дату в поддерживающих его СУБД. Для текущих даты и времени обычно применяются отдельные timestamp-функции.

Как посчитать разницу дат в SQL и использовать DATEDIFF?

Синтаксис зависит от СУБД. В одних диалектах есть функция DATEDIFF, в других даты вычитают напрямую или используют функции для вычисления интервала между значениями.

Практика функций даты в SQL

В SQL Arena можно продолжить практику на задачах с отдельными таблицами и автоматической проверкой на скрытых данных. Бесплатно доступны 292 задачи на PostgreSQL, MySQL, ClickHouse и BigQuery, а для следующего шага можно пройти трек «SQL с нуля → Аналитик».

Решать задачи по датам