DATE_TRUNC в SQL: недели, месяцы и правильные границы периода
Практическая работа с DATE_TRUNC в PostgreSQL: группировка по неделям и месяцам, timezone, границы периода и сравнение полных интервалов.
Содержание статьи
Группировка по датам кажется простой, пока команда не сталкивается с часовым поясом, началом недели и неполным текущим месяцем. Ошибка в одном преобразовании разносит данные по периодам и меняет тренд. Почему одна и та же дата попадает в разные недели в разных отчётах?
Сигнал в данных
Почему одна и та же дата попадает в разные недели в разных отчётах?
Группировка по датам кажется простой, пока команда не сталкивается с часовым поясом, началом недели и неполным текущим месяцем. Ошибка в одном преобразовании разносит данные по периодам и меняет тренд.
Событие в 23:30 UTC может относиться к следующему календарному дню для Москвы. В отчёте по регистрации это меняет когорту и последующий retention.
Как устроен расчёт
После DATE_TRUNC одна строка должна быть period_start × segment. Не группируй по форматированной строке даты, если потом потребуется сортировка и арифметика.
Приведи timestamp к рабочему timezone до DATE_TRUNC, назови начало периода и исключи неполный текущий интервал из сравнений. Для календарных отчётов держи отдельную таблицу дат.
Если показатель строится по событиям, отдельно проверь повторную отправку, идентичность пользователя и часовой пояс. Если данные приходят из бизнес-системы, сопоставь техническое поле с тем, как команда реально принимает решение.
вопрос → объект → период → расчёт → проверка → решениеЛюбой пропущенный шаг может изменить смысл итогового числа.
Практический сценарий
Событие в 23:30 UTC может относиться к следующему календарному дню для Москвы. В отчёте по регистрации это меняет когорту и последующий retention.
Не копируй пример в рабочий отчёт вслепую. Сначала замени названия таблиц и полей, проверь кардинальность связей и запиши, какие строки должны попасть в результат. Хорошая адаптация сохраняет логику, но делает допущения видимыми.
| Параметр | Пример | Что проверить |
|---|---|---|
| Timezone | Europe/Moscow | где преобразуется timestamp |
| Неделя | понедельник | ISO или календарное правило |
| Незрелость | исключить текущий день | полный ли период |
SELECT DATE_TRUNC('day', event_at AT TIME ZONE 'Europe/Moscow') AS day_start, COUNT(DISTINCT user_id) AS active_users\nFROM events\nWHERE event_at >= TIMESTAMP '2026-07-01 00:00:00+03'\nGROUP BY 1\nORDER BY 1;Контрольные случаи
Опасны DATE вместо timestamp, локальная timezone сессии, ISO-недели и сравнение месяца, который ещё не закончился.
Отдельно протестируй пустой результат, NULL, дубль, граничную дату и объект без связанной записи. Эти случаи не являются редкими исключениями: именно они чаще всего превращают рабочий показатель в красивую, но неверную цифру.
- Не смешивай зрелые и незрелые периоды без отдельной подписи.
- Не заменяй проверку качества тем, что запрос просто выполнился.
- Не делай причинный вывод из одного разреза.
Чтение визуализации
График здесь нужен не для украшения статьи. Он помогает увидеть форму сигнала: тренд, разрыв между сегментами, хвост распределения или этап, на котором теряется объект. Сначала прочитай оси и единицы, затем сравни с таблицей и только после этого формулируй вывод.
На визуализации «Один поток событий по календарным периодам» сравнивай не только максимальное значение. Проверь, одинаковы ли базы, не скрыта ли неполная дата и не меняется ли знаменатель от категории к категории.
Условный пример: выбор timezone меняет границу дня и вид дневного ряда.
Небольшое упражнение
Возьми события на границе полуночи и недели. Сгруппируй их в UTC и рабочей зоне, затем объясни, какой вариант соответствует продуктовой логике.
После упражнения напиши вывод в двух версиях. Первая — техническая: какие строки и условия дали результат. Вторая — для команды: что изменилось, насколько это надёжно и какое действие стоит проверить. Если эти версии противоречат друг другу, вернись к определению показателя.
- Собери контрольный пример из пяти-десяти строк.
- Сверь итог с независимым способом расчёта.
- Проверь хотя бы один крайний случай.
- Зафиксируй дату, версию схемы и ограничение.
Что передать команде
Зафиксируй timezone и календарь в словаре метрик. Если бизнес использует финансовые периоды, не подменяй их календарными месяцами.
Сильный аналитический материал не обещает абсолютной уверенности. Он показывает, как получить число, где оно может ошибиться и какое решение можно принять уже сейчас. Такой формат хорошо переносится в дашборд, SQL-тренажёр, собеседование и рабочее обсуждение с командой.
Материалы по теме
BETWEEN в SQL и фильтр по датам: как не потерять последний день
Как правильно фильтровать даты в SQL: BETWEEN, полуоткрытые интервалы, timestamp, часовые пояса и полные календарные периоды.

SQL даты и время в аналитике: периоды, недели и возраст пользователя
Как работать с датами в SQL: строить полные периоды, группировать события по дням и неделям, считать возраст пользователя и не ошибаться на границах интервалов.

CAST и типы данных в SQL: почему конверсия равна нулю
Целочисленное деление, numeric против float, текст в число и дату, приведение типов в WHERE и индексы: как готовить данные так, чтобы расчёт не врал молча.