Урок 3.4 · Время чтения: ~9 мин
Функции работы с датой и временем в SQL позволяют извлекать, изменять и форматировать значения дат и времени. Эти функции широко используются для анализа временных данных, фильтрации по дате, вычисления интервалов и форматирования вывода. В этом уроке рассмотрены наиболее часто используемые функции с примерами на базе данных Sakila.
Основные функции даты и времени в SQL
Важно: CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP во многих СУБД относятся к специальным SQL-выражениям (или алиасам соответствующих функций), а не к "обычным" функциям вида NAME(arg1, arg2, ...). Из-за этого синтаксис и детали поведения могут отличаться между СУБД.
Общие функции даты и времени
CURRENT_DATE - Специальное выражение, возвращающее текущую дату (без времени).
Синтаксис:
CURRENT_DATE
Пример:
SELECT CURRENT_DATE AS today;
Результат: Текущая дата, например: 2025-06-03
CURRENT_TIME - Специальное выражение/алиас, возвращающее текущее время (без даты).
Синтаксис:
CURRENT_TIME
CURRENT_TIME()
CURRENT_TIME(precision)
Пример:
SELECT CURRENT_TIME AS now_time;
Результат: Текущее время. С указанием точности (например, CURRENT_TIME(3)) возвращается время с долями секунды.
CURRENT_TIMESTAMP / NOW() - Возвращает текущие дату и время (часто как специальное выражение/алиас).
Синтаксис:
CURRENT_TIMESTAMP
CURRENT_TIMESTAMP()
CURRENT_TIMESTAMP(precision)
NOW()
Пример:
SELECT CURRENT_TIMESTAMP AS now_datetime;
SELECT NOW() AS now_datetime;
Результат: Текущие дата и время, например: 2025-06-03 14:25:30
Важно: в большинстве СУБД CURRENT_DATE/CURRENT_TIME/CURRENT_TIMESTAMP фиксируются на момент начала выполнения запроса (а в некоторых режимах - на момент начала транзакции). Поэтому в рамках одного запроса все строки обычно получают одно и то же значение.
Если нужна "текущая метка времени" именно в момент вычисления для конкретной строки, используют другие функции, зависящие от СУБД (например, SYSDATE() в MySQL/MariaDB, clock_timestamp() в PostgreSQL).
DATE() - Извлекает только дату из значения даты и времени.
Синтаксис:
DATE(datetime_value)
Пример:
SELECT DATE(rental_date) AS rental_only_date
FROM rental
LIMIT 3;
Результат: Возвращает только дату из столбца rental_date.
TIME() - Извлекает только время из значения даты и времени.
Синтаксис:
TIME(datetime_value)
Пример:
SELECT TIME(rental_date) AS rental_only_time
FROM rental
LIMIT 3;
Результат: Возвращает только время из столбца rental_date.
YEAR() - Извлекает год из значения даты.
Синтаксис:
YEAR(date_value)
Пример:
SELECT YEAR(rental_date) AS rental_year
FROM rental
LIMIT 3;
Результат: Возвращает год из даты аренды.
MONTH() - Извлекает месяц из значения даты.
Синтаксис:
MONTH(date_value)
Пример:
SELECT MONTH(rental_date) AS rental_month
FROM rental
LIMIT 3;
Результат: Возвращает месяц из даты аренды.
DAY() - Извлекает день месяца из значения даты.
Синтаксис:
DAY(date_value)
Пример:
SELECT DAY(rental_date) AS rental_day
FROM rental
LIMIT 3;
Результат: Возвращает день месяца из даты аренды.
WEEK() - Возвращает номер недели для даты (MySQL/MariaDB).
Синтаксис:
WEEK(date_value)
WEEK(date_value, mode)
Пример:
SELECT rental_id, rental_date, WEEK(rental_date) AS rental_week
FROM rental
LIMIT 5;
Результат: Возвращает номер недели для каждой даты аренды.
WEEK() часто используют в WHERE и GROUP BY, когда нужно строить недельные отчеты. Важно учитывать параметр mode: он влияет на то, какой день считается началом недели и как определяется первая неделя года.
DATE_ADD() - Добавляет указанный интервал к дате.
Синтаксис:
DATE_ADD(date, INTERVAL value unit)
Пример:
SELECT DATE_ADD(rental_date, INTERVAL 7 DAY) AS return_due
FROM rental
LIMIT 3;
Результат: Возвращает дату, увеличенную на 7 дней.
DATE_SUB() - Вычитает указанный интервал из даты.
Синтаксис:
DATE_SUB(date, INTERVAL value unit)
Пример:
SELECT DATE_SUB(rental_date, INTERVAL 3 DAY) AS three_days_before
FROM rental
LIMIT 3;
Результат: Возвращает дату, уменьшенную на 3 дня.
DATEDIFF() - Возвращает количество дней между двумя датами.
Синтаксис:
DATEDIFF(date1, date2)
Пример:
SELECT DATEDIFF(return_date, rental_date) AS rental_duration
FROM rental
WHERE return_date IS NOT NULL
LIMIT 3;
Результат: Количество дней между датой возврата и датой аренды.
DATE_FORMAT() - Форматирует дату в заданном формате (MySQL).
Синтаксис:
DATE_FORMAT(date, format)
Пример:
SELECT DATE_FORMAT(rental_date, '%d.%m.%Y') AS formatted_date
FROM rental
LIMIT 3;
Результат: Дата в формате дд.мм.гггг, например: 03.06.2025
Общие спецификаторы формата:
%Y: Год (4 цифры)%m: Месяц (2 цифры)%d: День месяца (2 цифры)%H: Час (24-часовой формат)%i: Минуты%s: Секунды
STRFTIME() - Форматирует дату/время (SQLite, PostgreSQL).
Синтаксис:
STRFTIME(format, date)
Пример:
SELECT STRFTIME('%Y-%m-%d', rental_date) AS formatted_date
FROM rental
LIMIT 3;
Результат: Дата в формате гггг-мм-дд.
TIMESTAMPDIFF() - Разница между двумя датами/временем в заданных единицах (MySQL).
Синтаксис:
TIMESTAMPDIFF(unit, datetime1, datetime2)
Пример:
SELECT TIMESTAMPDIFF(DAY, rental_date, return_date) AS days_rented
FROM rental
WHERE return_date IS NOT NULL
LIMIT 3;
Результат: Количество дней между датой аренды и возврата.
EXTRACT() - Извлекает часть даты или времени (год, месяц, день и т.д.).
Синтаксис:
EXTRACT(part FROM date)
Пример:
SELECT EXTRACT(YEAR FROM rental_date) AS rental_year
FROM rental
LIMIT 3;
Результат: Извлекает год из даты аренды.
Практическое применение
- Нахождение фильмов, арендованных за последние 30 дней:
SELECT * FROM rental WHERE rental_date > DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY); - Подсчет количества аренд в каждом месяце:
SELECT YEAR(rental_date) AS year, MONTH(rental_date) AS month, COUNT(*) AS rentals FROM rental GROUP BY year, month ORDER BY year DESC, month DESC; - Форматирование даты аренды для отчета:
SELECT DATE_FORMAT(rental_date, '%d.%m.%Y') AS formatted_rental FROM rental LIMIT 5; - Группировка аренд по неделям:
SELECT YEAR(rental_date) AS year, WEEK(rental_date, 1) AS week_num, COUNT(*) AS rentals FROM rental GROUP BY year, week_num ORDER BY year DESC, week_num DESC;
Часто задаваемые вопросы
Когда использовать DATEDIFF(), а когда TIMESTAMPDIFF()?
DATEDIFF() возвращает разницу только в днях между двумя датами. TIMESTAMPDIFF() гибче: можно считать разницу в секундах, минутах, часах, днях, месяцах и других единицах.
Чем DATE() отличается от DATE_FORMAT()?
DATE() просто отбрасывает время и возвращает дату. DATE_FORMAT() формирует строковое представление даты в нужном формате, например '%d.%m.%Y'.
Зачем нужен второй аргумент в WEEK(date, mode)?
Параметр mode задает правила расчета номера недели: первый день недели и логику определения первой недели года. Это важно для единообразной отчетности.
Почему функции с датой могут работать по-разному в разных СУБД?
Разные СУБД могут по-разному трактовать синтаксис, таймзоны, форматы и календарные правила. Поэтому для кросс-СУБД запросов нужно проверять документацию конкретного движка.
Вопросы для собеседования
Как вы объясните разницу между CURRENT_DATE и CURRENT_TIMESTAMP?
CURRENT_DATE возвращает только текущую дату, без времени. CURRENT_TIMESTAMP возвращает и дату, и время, поэтому его используют, когда важна точная временная метка.
Когда вы выберете WEEK() вместо группировки по дням или месяцам?
WEEK() полезен для недельной аналитики: сравнения динамики продаж, аренд или заказов по неделям. Это компромисс между слишком детальным дневным и слишком грубым месячным уровнем.
Какие риски у фильтрации по функции в WHERE, например DATE(rental_date) = ...?
Такой фильтр может мешать использованию индекса по исходному столбцу и ухудшать производительность. Часто лучше фильтровать диапазоном (>= и <) без оборачивания столбца функцией.
Как сделать форматирование даты переносимым между СУБД?
Нужно учитывать, что форматирующие функции отличаются (DATE_FORMAT, TO_CHAR, STRFTIME). Для переносимости обычно выносят форматирование в слой приложения или используют СУБД-специфичные версии запросов.
Ключевые выводы этого урока:
- Функции даты и времени помогают фильтровать, агрегировать и форматировать временные данные прямо в SQL.
CURRENT_DATE,CURRENT_TIMEиCURRENT_TIMESTAMPчасто являются специальными выражениями, а их поведение зависит от СУБД.DATE_ADD,DATE_SUB,DATEDIFFиTIMESTAMPDIFFрешают задачи работы с интервалами.WEEK()удобен для недельной аналитики, но важно явно выбратьmode.- Для кросс-СУБД запросов нужно учитывать различия синтаксиса и календарной логики.
В следующем уроке мы разберем строковые функции SQL и научимся обрабатывать текстовые данные в запросах.