Функции для работы с датой и временем
Даты, время, интервалы в PostgreSQL
Теория
В PostgreSQL существует еще одна категория функций, функции для работы с датой и временем. Они помогают нам:
• получить текущую дату и текущее время;
• вытащить из даты год, месяц, день или час;
• округлить дату и время до начала месяца, дня или часа;
• прибавить или отнять нужный интервал;
• посчитать разницу между двумя датами.
Дата и время в SQL — это не просто текст. Это полноценные значения, с которыми можно выполнять вычисления, сравнения и преобразования.
В учебных таблицах у нас есть и обычные даты, и дата со временем. Например, registration_date и hire_date — это DATE, а order_date — уже TIMESTAMP. Поэтому в одних местах мы работаем сразу со временем, а в других при необходимости явно берём только дату через ::date.
Синтаксис
SELECT CURRENT_DATE,
CURRENT_TIME,
CURRENT_TIMESTAMP,
EXTRACT(YEAR FROM registration_date),
DATE_TRUNC('month', order_date)
FROM table_name;
SELECT order_date + INTERVAL '7 days',
AGE(CURRENT_DATE::timestamp, hire_date::timestamp)
FROM table_name;
SQL
Компактная шпаргалка по самым полезным функциям и конструкциям.
| Пример | Результат | Что делает |
|---|---|---|
| CURRENT_DATE | Текущая дата | Возвращает сегодняшнюю дату. |
| CURRENT_TIME | Текущее время | Возвращает текущее время. |
| CURRENT_TIMESTAMP | Дата и время | Возвращает текущие дату и время вместе. |
| NOW() | Дата и время | Практически тот же сценарий, что и у CURRENT_TIMESTAMP. |
| EXTRACT(YEAR FROM order_date) | 2024 | Достаёт нужную часть из даты или времени. |
| DATE_TRUNC('month', CURRENT_TIMESTAMP) | Начало месяца | Обрезает более мелкие части даты и времени. |
| order_date + INTERVAL '7 days' | Дата и время через 7 дней | Прибавляет к дате нужный интервал. |
| AGE(CURRENT_DATE::timestamp, hire_date::timestamp) | Интервал между датами | Показывает разницу между двумя датами в более человеческом виде. |
| order_date::date - DATE '2024-01-01' | число дней | Показывает разницу в днях между двумя датами. |
Теперь по классике разберем важные моменты.
1. CURRENT_DATE, CURRENT_TIME и CURRENT_TIMESTAMP берут значение на текущий момент.
Это удобно, когда нужно сравнить данные с сегодняшней датой или просто показать текущее время прямо в запросе.
2. EXTRACT нужен, когда из даты или времени нужна только одна часть.
Например, только год, только месяц, только день или только час. Поэтому записи вроде EXTRACT(YEAR FROM order_date) и EXTRACT(MONTH FROM registration_date) встречаются очень часто.
3. DATE_TRUNC не вытаскивает часть даты, а усекает значение.
Например, если обрезать (усечь) до месяца, то всё внутри месяца сведётся к его началу. Это удобно для отчётов по дням, месяцам и годам.
4. Прибавление интервала — это обычная рабочая операция.
Если нужно получить дату через 7 дней, через 1 месяц или через 2 часа, рядом с датой или временем просто пишут INTERVAL. Например: order_date + INTERVAL '7 days'.
5. AGE и обычное вычитание даты — это не одно и то же.
AGE возвращает интервал в более человеческом виде: годы, месяцы, дни. А вычитание одной даты из другой чаще всего даёт просто количество дней.
6. Дата и дата со временем — это не одно и то же.
Если поле хранится как timestamp, как у order_date, то при расчёте разницы именно в днях часто нужно явно взять только дату. Для этого удобно использовать запись order_date::date.
7. Результат функций даты и времени лучше сразу называть через псевдоним.
Например: EXTRACT(YEAR FROM order_date) AS order_year или order_date + INTERVAL '7 days' AS delivery_deadline. Так результат намного легче читать.
Примеры
1. Смотрим на текущую дату и текущее время
🔄 Попробуйте изменить запрос:
- • Запустите запрос несколько раз подряд и посмотрите, как меняется время
- • Вычтите из CURRENT_TIMESTAMP функцию NOW()
2. Достаём из даты год, месяц и день
🔄 Попробуйте изменить запрос:
- • Замените YEAR на HOUR и посмотрите, как теперь ведёт себя order_date
- • Попробуйте тот же приём на registration_date из таблицы users
3. Округляем дату и время до начала месяца
🔄 Попробуйте изменить запрос:
- • Замените 'month' на 'day' и посмотрите, как изменится результат
- • Попробуйте применить ту же функцию к CURRENT_TIMESTAMP без таблицы
4. Прибавляем к дате нужный интервал
🔄 Попробуйте изменить запрос:
- • Замените '7 days' на '14 days'
- • Попробуйте вместо '1 month' указать '2 months'
5. Считаем стаж работника от даты найма
🔄 Попробуйте изменить запрос:
- • Замените CURRENT_DATE::timestamp на конкретную дату через TIMESTAMP '2025-01-01 00:00:00'
- • Попробуйте посчитать разницу между CURRENT_DATE::timestamp и registration_date::timestamp в таблице users
6. Считаем разницу между датами в днях
🔄 Попробуйте изменить запрос:
- • Замените дату '2024-01-01'::date на '2024-06-01'::date
- • Попробуйте вычислить разницу через функцию AGE
7. Фильтруем заказы за последние 7 дней
🔄 Попробуйте изменить запрос:
- • Замените '7 days' на '14 days'
- • Попробуйте сдвинуть опорную дату с '2024-05-10 00:00:00'::timestamp на '2024-04-20 00:00:00'::timestamp
8. Используем часть даты прямо в фильтрации
🔄 Попробуйте изменить запрос:
- • Замените 6 на 12
- • Попробуйте вместо месяца фильтровать по году через EXTRACT(YEAR FROM registration_date)
Типичные ошибки
Путают дату как значение и дату как текст
Записи вроде CURRENT_DATE или DATE '2024-01-01' — это работа именно с датой, а не просто с текстом. Это важно для вычислений и сравнений.
Думают, что EXTRACT возвращает новую дату
Нет. EXTRACT достаёт только одну часть: например год, месяц, день или час.
Путают DATE_TRUNC и EXTRACT
EXTRACT достаёт одну часть из даты. DATE_TRUNC укрупняет всё значение до дня, месяца, года и так далее.
Забывают, что у поля может быть и дата, и время
Если поле хранится как timestamp, как у order_date, то при расчёте разницы в днях часто нужно явно взять только дату: order_date::date.
Не понимают разницу между AGE и вычитанием дат
AGE возвращает интервал в более человеческом виде, а простое вычитание чаще всего даёт количество дней. Это два разных подхода.
Прибавляют к дате число вместо интервала и потом не понимают результат
Когда нужен осознанный сдвиг по дням, неделям или месяцам, лучше явно писать INTERVAL, например order_date + INTERVAL '7 days'.
Оставляют вычисляемый столбец без понятного имени
Лучше сразу давать результату псевдоним: например order_date + INTERVAL '7 days' AS delivery_deadline или EXTRACT(YEAR FROM order_date) AS order_year.
Практика
Проверь себя
Ответьте на вопросы, чтобы закрепить материал: