> SmartGate 41 752 9863

Функции для работы с датой и временем

Даты, время, интервалы в PostgreSQL

Теория

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

В 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. Достаём из даты год, месяц и день

Функция EXTRACT удобна, когда из даты нужна только одна часть. Например, отдельно год или отдельно месяц заказа.

🔄 Попробуйте изменить запрос:

  • • Замените YEAR на HOUR и посмотрите, как теперь ведёт себя order_date
  • • Попробуйте тот же приём на registration_date из таблицы users

3. Округляем дату и время до начала месяца

Функция DATE_TRUNC усекает всё после месяца и оставляет его начало. Это удобно, когда нужно привести разные даты одного месяца к одной общей точке.

🔄 Попробуйте изменить запрос:

  • • Замените 'month' на 'day' и посмотрите, как изменится результат
  • • Попробуйте применить ту же функцию к CURRENT_TIMESTAMP без таблицы

4. Прибавляем к дате нужный интервал

Такой запрос нужен, когда от даты события нужно посчитать определенный срок. Например, дату проверки, дату напоминания или условный срок доставки.

🔄 Попробуйте изменить запрос:

  • • Замените '7 days' на '14 days'
  • • Попробуйте вместо '1 month' указать '2 months'

5. Считаем стаж работника от даты найма

Функция AGE хорошо подходит для вопроса: сколько времени прошло между двумя датами. Здесь она показывает стаж сотрудника от даты найма до сегодняшнего дня.

🔄 Попробуйте изменить запрос:

  • • Замените CURRENT_DATE::timestamp на конкретную дату через TIMESTAMP '2025-01-01 00:00:00'
  • • Попробуйте посчитать разницу между CURRENT_DATE::timestamp и registration_date::timestamp в таблице users

6. Считаем разницу между датами в днях

Когда одна дата вычитается из другой, PostgreSQL возвращает количество дней. Это удобно для расчётов, где нужен не красивый интервал, а именно конкретное количество дней.

🔄 Попробуйте изменить запрос:

  • • Замените дату '2024-01-01'::date на '2024-06-01'::date
  • • Попробуйте вычислить разницу через функцию AGE

7. Фильтруем заказы за последние 7 дней

Идея такая: мы берём не один фиксированный день, а целый диапазон за последние 7 дней до выбранной даты. Это частый рабочий сценарий, когда нужно посмотреть недавние заказы, регистрации или другие события за нужный период.

🔄 Попробуйте изменить запрос:

  • • Замените '7 days' на '14 days'
  • • Попробуйте сдвинуть опорную дату с '2024-05-10 00:00:00'::timestamp на '2024-04-20 00:00:00'::timestamp

8. Используем часть даты прямо в фильтрации

В этом примере результат функции используется не только в SELECT, но и в WHERE. Так легко, например, найти пользователей, зарегистрированных в нужном месяце.

🔄 Попробуйте изменить запрос:

  • • Замените 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.

Практика

Проверь себя

Ответьте на вопросы, чтобы закрепить материал:

1
Какая конструкция вернёт только текущую дату, без времени?
2
Что делает выражение DATE_TRUNC('month', order_date)?
3
Что вернёт выражение EXTRACT(MONTH FROM DATE '2024-11-08')? Введите только число.
4
Что вернёт выражение DATE '2024-03-10' - DATE '2024-03-01'? Введите только число.
5
В чём главная разница между AGE(CURRENT_DATE::timestamp, hire_date::timestamp) и выражением CURRENT_DATE - hire_date?
6
Напишите запрос к таблице workers, который выведет worker_id, first_name, hire_date и столбец hire_year_start. В hire_year_start нужно показать начало года найма через DATE_TRUNC. Оставьте только работников из отделов 2 и 3, у которых hire_date не раньше DATE '2021-01-01'. Отсортируйте результат по hire_date от более ранней к более поздней, а потом по worker_id.
7
Напишите запрос к таблице orders, который выведет order_id, order_date, status и столбец order_minute. В order_minute нужно показать минуту из order_date. Оставьте только заказы со статусом 'доставлен', у которых order_date не раньше '2024-05-01 00:00:00'::timestamp и раньше '2024-06-01 00:00:00'::timestamp. Отсортируйте результат сначала по order_minute от большей к меньшей, а потом по order_date от более поздней к более ранней.
8
Напишите запрос к таблице workers, который выведет worker_id, first_name, hire_date и столбец probation_end. В probation_end нужно показать дату окончания испытательного срока, если считать его равным 90 дням после найма. Оставьте только работников из отделов 1 и 2, у которых дата найма указана. Сначала должны идти более ранние даты найма.