Hey,
I need to find three previous working days from a given date, omitting weekends and holidays. This isn't a hard task in itself, but it seems that the way I was going to do it would be overly complicated, so I thought I'd ask for your opinion first.
To make things more interesting, let's make this a contest. I'm offering 300 as a bounty to whoever comes up with the shortest, cleanest solution that adheres to this specification:
- Write a function that returns three previous working days from a given date
- Working day is defined as any day that is not saturday or sunday and isn't an holiday
- The function knows the holidays for the year of the given date and can take these into account
- The function accepts one parameter, the date, in
Y-m-d
format - The function returns an array with three dates in
Y-m-d
format, sorted from oldest to newest.
Extra:
- The function can find also the next three working days in addition to the previous three
An example of the holidays array:
$holidays = array(
'2010-01-01',
'2010-01-06',
'2010-04-02',
'2010-04-04',
'2010-04-05',
'2010-05-01',
'2010-05-13',
'2010-05-23',
'2010-06-26',
'2010-11-06',
'2010-12-06',
'2010-12-25',
'2010-12-26'
);
Note that in the real scenario, the holidays aren't hardcoded but come from get_holidays($year)
function. You can include / use that in your answer if you wish.
As I'm offering a bounty, that means there will be at least three days before I can mark an answer as accepted (2 days to add a bounty, 1 day until I can accept).
Note
If you use a fixed day length such as 86400 seconds to jump from day to another, you'll run into problems with daylight savings time. Use strtotime('-1 day', $timestamp)
instead.
An example of this problem:
Final solution
Here's the final solution I ended up using, adapted from Keith Minkler's idea of using strtotime
's last weekday
. Detects the direction from the passed count, if negative, searches backwards, and forwards on positive:
function working_days($date, $count) {
$working_days = array();
$direction = $count < 0 ? 'last' : 'next';
$holidays = get_holidays(date("Y", strtotime($date)));
while(count($working_days) < abs($count)) {
$date = date("Y-m-d", strtotime("$direction weekday", strtotime($date)));
if(!in_array($date, $holidays)) {
$working_days[] = $date;
}
}
sort($working_days);
return $working_days;
}