4
votes

I am trying to get the next 3 days using php but if the date is a weekend or a defined holiday I would like to skip that date.

For example if the date is Monday, December 23, 2013 My holiday dates are array('2013-12-24', '2013-12-25'); The script would return

Monday, December 23, 2013
Thursday, December 26, 2013
Friday, December 27, 2013
Monday, December 30, 2013

Her is my current code:

$arr_date = explode('-', '2013-12-23');
$counter = 0;
for ($iLoop = 0; $iLoop < 4; $iLoop++)
{
    $dayOfTheWeek = date("N", mktime(0, 0, 0, $arr_date[1], $arr_date[2]+$counter, $arr_date[0]));
    if ($dayOfTheWeek == 6) { $counter += 2; }
    $date = date("Y-m-d", mktime(0, 0, 0, $arr_date[1], $arr_date[2]+$counter, $arr_date[0]));
    echo $date;
    $counter++;
}

The issue I am having is I am not sure to how to even go about excluding holidays dates.

2
This answer has a lot of logic you can use for thisJohn Conde
OK. So what have you attempted so far? What is not working?Mike Brant
Also, please show the code you are currently working on as per Stack Overflow guidelines.NobleUplift
@NobleUplift that was a tpying error, it was supposed to be a 23Robert E. McIntosh
I am putting the code together now.Robert E. McIntosh

2 Answers

4
votes

Use a DateTime to recurse over the next days and have a string comparison check to see if the next generated day belongs in the holiday or weekend arrays using in_array

$holidays = array('12-24', '12-25');
$weekend = array('Sun','Sat');
$date = new DateTime('2013-12-23');
$nextDay = clone $date;
$i = 0; // We have 0 future dates to start with
$nextDates = array(); // Empty array to hold the next 3 dates
while ($i < 3)
{
    $nextDay->add(new DateInterval('P1D')); // Add 1 day
    if (in_array($nextDay->format('m-d'), $holidays)) continue; // Don't include year to ensure the check is year independent
    // Note that you may need to do more complicated things for special holidays that don't use specific dates like "the last Friday of this month"
    if (in_array($nextDay->format('D'), $weekend)) continue;
    // These next lines will only execute if continue isn't called for this iteration
    $nextDates[] = $nextDay->format('Y-m-d');
    $i++;
}

Using the suggestion of isset() for O(1) instead of O(n):

$holidays = array('12-24' => '', '12-25' => '');
$weekend = array('Sun' => '','Sat' => '');
$date = new DateTime('2013-12-23');
$dayInterval = new DateInterval('P1D');
$nextDay = clone $date;
$i = 0;
$nextDates = array();
while ($i < 3)
{
    $nextDay->add($dayInterval);
    if (isset($holidays[$nextDay->format('m-d')])) continue;
    if (isset($weekend[$nextDay->format('D')])) continue;
    $nextDates[] = $nextDay->format('Y-m-d');
    $i++;
}
4
votes

Here is a simple example of how to get number of working days between 2 dates; which you can simply modify to fit your needs:

function number_of_working_dates($from, $days) {
    $workingDays = [1, 2, 3, 4, 5]; # date format = N (1 = Monday, ...)
    $holidayDays = ['*-12-25', '*-01-01', '2013-12-24', '2013-12-25']; # variable and fixed holidays

    $from = new DateTime($from);
    $dates = [];
    $dates[] = $from->format('Y-m-d');
    while ($days) {
        $from->modify('+1 day');

        if (!in_array($from->format('N'), $workingDays)) continue;
        if (in_array($from->format('Y-m-d'), $holidayDays)) continue;
        if (in_array($from->format('*-m-d'), $holidayDays)) continue;

        $dates[] = $from->format('Y-m-d');
        $days--;
    }
    return $dates;
}

print_r( number_of_working_dates('2013-12-23', 3) );

demo