← К списку уроков
SQL·Средний·12 мин

Функции работы с датами в SQL

DATE_TRUNC, EXTRACT, DATE_PART — как группировать и форматировать даты.

Функции работы с датами в SQL

Даты — главная боль и главное удовольствие SQL-аналитика. От «выручка по месяцам» до «сколько прошло с последнего входа» — всё через date-функции.

Текущая дата/время

SELECT
    CURRENT_DATE,             -- 2026-06-17
    CURRENT_TIME,             -- 14:30:25
    CURRENT_TIMESTAMP,        -- 2026-06-17 14:30:25
    NOW();                    -- то же что CURRENT_TIMESTAMP

Извлечение частей

EXTRACT(YEAR FROM created_at)    -- 2026
EXTRACT(MONTH FROM created_at)   -- 6
EXTRACT(DAY FROM created_at)     -- 17
EXTRACT(DOW FROM created_at)     -- день недели 0-6
EXTRACT(HOUR FROM created_at)    -- 14

DATE_TRUNC — округление вниз

Самая полезная функция для агрегаций:

DATE_TRUNC('day', created_at)     -- 2026-06-17 00:00:00
DATE_TRUNC('week', created_at)    -- начало недели (понедельник)
DATE_TRUNC('month', created_at)   -- 2026-06-01
DATE_TRUNC('quarter', created_at) -- 2026-04-01
DATE_TRUNC('year', created_at)    -- 2026-01-01

Выручка по месяцам:

SELECT
    DATE_TRUNC('month', created_at) AS month,
    SUM(amount) AS revenue
FROM orders
GROUP BY 1
ORDER BY 1;

Арифметика с датами

created_at + INTERVAL '7 days'
created_at - INTERVAL '1 month'
CURRENT_DATE - created_at        -- результат INTERVAL
EXTRACT(DAY FROM CURRENT_DATE - created_at)  -- N дней

Юзеры активные за 30 дней:

WHERE last_login >= CURRENT_DATE - INTERVAL '30 days'

AGE — возраст / время с события

AGE(birth_date)                            -- сколько лет/месяцев/дней
AGE(CURRENT_DATE, birth_date)              -- то же явно
DATE_PART('year', AGE(birth_date))         -- только годы

Форматирование

TO_CHAR(created_at, 'YYYY-MM-DD')         -- 2026-06-17
TO_CHAR(created_at, 'Mon DD')             -- Jun 17
TO_CHAR(created_at, 'Day')                -- Wednesday

TIMESTAMP vs TIMESTAMPTZ

  • TIMESTAMP — дата+время без timezone
  • TIMESTAMPTZ — с учётом timezone (рекомендуется для production)

Всегда работай в UTC в БД, конвертируй на показе:

created_at AT TIME ZONE 'Asia/Almaty'

Что важно запомнить

  • Для агрегаций по дням/неделям/месяцам — DATE_TRUNC
  • EXTRACT(MONTH FROM ...) → 6, но DATE_TRUNC('month', ...) → 2026-06-01. Второе лучше: сохраняет год
  • CURRENT_DATE - INTERVAL '7 days' — стандарт для «за последнюю неделю»
  • Никогда не сравнивай TIMESTAMP со строкой — кастуй явно
  • На собеседовании: «выручка по месяцам последний год» = DATE_TRUNC('month', ...) WHERE >= CURRENT_DATE - INTERVAL '12 months'