Задача
Вы хотите добавить время к значению даты или к значению дата-и-время.
Решение
Используйте функции DATE_ADD() и DATE_SUB(), специально предназначенные для выполнения арифметических операций с датами. Вы также можете применять TO_DAYS() и FROM_DAYS() или UNIX_TIMESTAMP() и FROM_UNIXTIME().
Обсуждение
Арифметические операции с датами чуть сложнее, чем со временем, из-за переменной длины месяцев и годов. Поэтому MySQL предлагает специальные функции DATE_ADD() и DATE_SUB() для сложения интервалов с датами и вычитания из них.1 Функции принимают значение даты d и интервал в таком формате:
DATE_ADD(d,INTERVAL значение единица)
DATE_SUB(d,INTERVAL значение единица)
где единица – это единица измерения интервала, а значение – выражение, определяющее количество таких единиц. К наиболее распространенным относятся такие спецификаторы единиц, как YEAR, MONTH, DAY, HOUR, MINUTE и SECOND (полный список приведен в руководстве по MySQL). Обратите внимание на то, что единица измерения указывается не во множественном, а в единственном числе.
С помощью функций DATE_ADD() и DATE_SUB() можно выполнять следующие арифметические операции:
• Определить дату, которая наступит через три дня после сегодняшней:
mysql> SELECT CURDATE(), DATE_ADD(CURDATE(),INTERVAL 3 DAY);
+------------+------------------------------------+
| CURDATE() | DATE_ADD(CURDATE(),INTERVAL 3 DAY) |
+------------+------------------------------------+
| 2002-07-15 | 2002-07-18 |
+------------+------------------------------------+
• Узнать дату, наступившую неделю назад (для представления недельного интервала запрос использует значение 7 DAY, так как не существует единица измерения WEEK):mysql> SELECT CURDATE(), DATE_SUB(CURDATE(),INTERVAL 7 DAY);
+------------+------------------------------------+
| CURDATE() | DATE_SUB(CURDATE(),INTERVAL 7 DAY) |
+------------+------------------------------------+
| 2002-07-15 | 2002-07-08 |
+------------+------------------------------------+
• Если вам необходимо узнать и дату, и время, начните со значения DATETIME или TIMESTAMP. Чтобы ответить на вопрос: «Сколько времени будет через 60 часов?», выполните такой запрос:
mysql> SELECT NOW(), DATE_ADD(NOW(),INTERVAL 60 HOUR);
+---------------------+----------------------------------+
| NOW() | DATE_ADD(NOW(),INTERVAL 60 HOUR) |
+---------------------+----------------------------------+
| 2002-07-15 11:31:17 | 2002-07-17 23:31:17 |
+---------------------+----------------------------------+
• Некоторые спецификаторы интервалов включают и дату, и время. Следующий запрос добавляет к текущим дате и времени четырнадцать с половиной часов:
mysql> SELECT NOW(), DATE_ADD(NOW(),INTERVAL '14:30' HOUR_MINUTE);
+---------------------+----------------------------------------------+
| NOW() | DATE_ADD(NOW(),INTERVAL '14:30' HOUR_MINUTE) |
+---------------------+----------------------------------------------+
| 2002-07-15 11:31:24 | 2002-07-16 02:01:24 |
+---------------------+----------------------------------------------+
Аналогично можно добавить 3 дня и 4 часа:
mysql> SELECT NOW(), DATE_ADD(NOW(),INTERVAL '3 4' DAY_HOUR);
+---------------------+-----------------------------------------+
| NOW() | DATE_ADD(NOW(),INTERVAL '3 4' DAY_HOUR) |
+---------------------+-----------------------------------------+
| 2002-07-15 11:31:30 | 2002-07-18 15:31:30 |
+---------------------+-----------------------------------------+
Функции DATE_ADD() и DATE_SUB() являются взаимозаменяемыми, так как одна из них – то же, что другая с интервалом противоположного знака. Например, два такие вызова эквиваленты для любого значения даты d:
DATE_ADD(d,INTERVAL -3 MONTH)
DATE_SUB(d,INTERVAL 3 MONTH)
Начиная с MySQL 3.23.4, можно использовать для сложения и вычитания интервалов дат операторы + и -:
mysql> SELECT CURDATE(), CURDATE() + INTERVAL 1 YEAR;
+------------+-----------------------------+
| CURDATE() | CURDATE() + INTERVAL 1 YEAR |
+------------+-----------------------------+
| 2002-07-15 | 2003-07-15 |
+------------+-----------------------------+
mysql> SELECT NOW(), NOW() - INTERVAL 24 HOUR;
+---------------------+--------------------------+
| NOW() | NOW() - INTERVAL 24 HOUR |
+---------------------+--------------------------+
| 2002-07-15 11:31:48 | 2002-07-14 11:31:48 |
+---------------------+--------------------------+
Для добавления интервалов к дате или значению дата-и-время можно также использовать функции преобразования в базовые единицы и обратно. Например, чтобы сдвинуть дату вперед или назад на неделю (семь дней), используйте функции TO_DAYS() и FROM_DAYS():
mysql> SET @d = '2002-01-01';
mysql> SELECT @d AS date,
-> FROM_DAYS(TO_DAYS(@d) + 7) AS 'date + 1 week',
-> FROM_DAYS(TO_DAYS(@d) - 7) AS 'date - 1 week';
+------------+---------------+---------------+
| date | date + 1 week | date - 1 week |
+------------+---------------+---------------+
| 2002-01-01 | 2002-01-08 | 2001-12-25 |
+------------+---------------+---------------+
Функция TO_DAYS() умеет вдобавок преобразовывать значения DATETIME и TIMESTAMP в дни, что удобно для тех, кому не нужна часть времени:
mysql> SET @dt = '2002-01-01 12:30:45';
mysql> SELECT @dt AS datetime,
-> FROM_DAYS(TO_DAYS(@dt) + 7) AS 'datetime + 1 week',
-> FROM_DAYS(TO_DAYS(@dt) - 7) AS 'datetime - 1 week';
+---------------------+-------------------+-------------------+
| datetime | datetime + 1 week | datetime - 1 week |
+---------------------+-------------------+-------------------+
| 2002-01-01 12:30:45 | 2002-01-08 | 2001-12-25 |
+---------------------+-------------------+-------------------+
Для обеспечения точности работы со значениями DATETIME и TIMESTAMP используйте функции UNIX_TIMESTAMP() и FROM_UNIXTIME() вместо рассмотренных ранее. Изменим значение DATETIME на час (3600 секунд) вперед и назад:
mysql> SET @dt = '2002-01-01 09:00:00';
mysql> SELECT @dt AS datetime,
-> FROM_UNIXTIME(UNIX_TIMESTAMP(@dt) + 3600) AS 'datetime + 1 hour',
-> FROM_UNIXTIME(UNIX_TIMESTAMP(@dt) - 3600) AS 'datetime - 1 hour';
+---------------------+---------------------+---------------------+
| datetime | datetime + 1 hour | datetime - 1 hour |
+---------------------+---------------------+---------------------+
| 2002-01-01 09:00:00 | 2002-01-01 10:00:00 | 2002-01-01 08:00:00 |
+---------------------+---------------------+---------------------+
Для реализации последнего приема необходимо, чтобы и исходное, и результирующее значения попадали в разрешенный для значений TIMESTAMP диапазон (с 1970 года где-то по 2037 год).