Finding Dates for Weekdays of Other Weeks

5.27.1 Problem

You want to compute the date for some weekday of some other week.

5.27.2 Solution

Figure out the date for that weekday in the current week, then shift the result into the desired week.

5.27.3 Discussion

Calculating the date for a day of the week in some other week is a problem that breaks down into a day-within-week shift (using the formula given in the previous section) plus a week shift. These operations can be done in either order because the amount of shift within the week is the same whether or not you shift the reference date into a different week first. For example, to calculate Wednesday of a week by the preceding formula, n is 4. To compute the date for Wednesday two weeks ago, you can perform the day-within-week shift first, like this:

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 | +------------+------------+------------------+

Or you can perform the week shift first:

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 | +------------+------------+------------------+

Some applications need to determine dates such as the n-th instance of particular weekdays. For example, if you administer a payroll where paydays are the 2nd and 4th Thursdays of each month, you'd need to know what those dates are. One way to do this for any given month is to begin with the first-of-month date and shift it forward. It's easy enough to shift the date to the Thursday in that week; the trick is to figure out how many weeks forward to shift the result to reach the 2nd and 4th Thursdays. If the first of the month occurs on any day from Sunday through Thursday, you shift forward one week to reach the 2nd Thursday. If the first of the month occurs on Friday or later, you shift forward by two weeks. The 4th Thursday is of course two weeks after that.

The following Perl code implements this logic to find all paydays in the year 2002. It runs a loop that constructs the first-of-month date for the months of the year. For each month, it issues a query that determines the dates of the 2nd and 4th Thursdays:

my $year = 2002; print "MM/CCYY 2nd Thursday 4th Thursday "; 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 ", $month, $year, $thu2, $thu4; }

The output from the program looks like this:

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

Категории