MySQL / 5. Работа с датами и временем

Определение дат для дней других недель

Задача
Вы хотите вычислить дату некоторого дня некоторой недели (не текущей).

Решение
Определите дату этого дня недели для текущей недели, затем сместите результат в интересующую вас неделю.

</>Обсуждение
Вычисление даты дня недели какой-то другой недели – это задача, которая разбивается на сдвиг на значение дня недели (см. предыдущий раздел) и сдвиг на недели. Порядок выполнения операций не имеет значения, так как величина сдвига внутри недели не зависит от того, смещена ли исходная дата. Например, чтобы вычислить по приведенной ранее формуле, каким числом будет среда, возьмем n, равное 4. Чтобы вычислить дату среды, наступившей две недели назад, вы можете сначала выполнить сдвиг дня недели:

mysql> SET @target = -> DATE_SUB(DATE_ADD(CURDATE(),INTERVAL 4-DAYOFWEEK(CURDATE()) DAY),
-> INTERVAL 14 DAY);
mysql> SELECT CURDATE(), @target, DAYNAME(@target);

+--------------+---------------+------------------------+
| CURDATE() |    @target    | DAYNAME(@target) |
+--------------+---------------+------------------------+
| 2002-07-15 | 2002-07-03 |        Wednesday       |
+--------------+---------------+------------------------+

А можете сначала сдвинуть неделю:

mysql> SET @target =
-> DATE_ADD(DATE_SUB(CURDATE(),INTERVAL 14 DAY),
-> INTERVAL 4-DAYOFWEEK(CURDATE()) DAY);
mysql> SELECT CURDATE(), @target, DAYNAME(@target);

+--------------+---------------+------------------------+
| CURDATE() |    @target    | DAYNAME(@target) |
+--------------+---------------+------------------------+
| 2002-07-15 | 2002-07-03 |         Wednesday       |
+--------------+---------------+------------------------+

Некоторым приложениям необходимо знать такие даты, как n-е вхождение какого-то дня недели. Например, если вы ведете платежную ведомость, выплаты по которой проводятся во 2-й и 4-й четверг каждого месяца, то вам необходимо знать даты этих дней. Одним из способов выполнения операции для текущего месяца будет нахождение первого дня месяца и его последующий сдвиг. Изменить дату на четверг текущей недели достаточно просто, проблема в том, как узнать, на сколько недель сдвигать результат, чтобы получить именно второй и четвертый четверги. Если первый день месяца выпадает на дни с воскресенья по четверг, то для получения второго четверга следует выполнить сдвиг на одну неделю. Если же первый день месяца выпадает на пятницу или последующие дни, сдвигаем на две недели. Четвертый четверг наступает, естественно, через две недели после второго.Приведем программу на Perl, вычисляющую все даты выдачи заработной платы в 2002 году. Выполняется цикл, который определяет дату первого дня месяца для всех месяцев года. Для каждого месяца выдается запрос, выводящий даты 2-го и 4-го четвергов:

my $year = 2002;
print "MM/CCYY 2nd Thursday 4th Thursday\n";
foreach my $month (1..12)
{
my $first = sprintf ("%04d-%02d-01", $year, $month);
my ($thu2, $thu4) = $dbh->selectrow_array (qq{
SELECT
DATE_ADD(
DATE_ADD(?,INTERVAL 5-DAYOFWEEK(?) DAY),
INTERVAL IF(DAYOFWEEK(?) <= 5, 7, 14) DAY),
DATE_ADD(
DATE_ADD(?,INTERVAL 5-DAYOFWEEK(?) DAY),
INTERVAL IF(DAYOFWEEK(?) <= 5, 21, 28) DAY)
}, undef, $first, $first, $first, $first, $first, $first);
printf "%02d/%04d %s %s\n", $month, $year, $thu2, $thu4;
}

Вывод программы выглядит следующим образом:

MM/CCYY 2nd Thursday 4th Thursday
01/2002 2002-01-10 2002-01-24
02/2002 2002-02-14 2002-02-28
03/2002 2002-03-14 2002-03-28
04/2002 2002-04-11 2002-04-25
05/2002 2002-05-09 2002-05-23
06/2002 2002-06-13 2002-06-27
07/2002 2002-07-11 2002-07-25
08/2002 2002-08-08 2002-08-22
09/2002 2002-09-12 2002-09-26
10/2002 2002-10-10 2002-10-24
11/2002 2002-11-14 2002-11-28
12/2002 2002-12-12 2002-12-26

Статьи по MySQL на эту тему:

Выбор записей по временным характеристикам
Вывод значений TIMESTAMP в удобном для чтения виде
Вычисления для високосных годов
Вычисления со значениями TIMESTAMP Задача
Использование значений TIMESTAMP

Вернуться в раздел: MySQL / 5. Работа с датами и временем