40

Does anyone have a PHP snippet to calculate the next business day for a given date? How does, for example, YYYY-MM-DD need to be converted to find out the next business day?

Example: For 03.04.2011 (DD-MM-YYYY) the next business day is 04.04.2011. For 08.04.2011 the next business day is 11.04.2011.

This is the variable containing the date I need to know the next business day for

$cubeTime['time'];

Variable contains: 2011-04-01 result of the snippet should be: 2011-04-04

Jonas
  • 121,568
  • 97
  • 310
  • 388
Marko
  • 1,537
  • 4
  • 22
  • 34

10 Answers10

122

Next Weekday

This finds the next weekday from a specific date (not including Saturday or Sunday):

echo date('Y-m-d', strtotime('2011-04-05 +1 Weekday'));

You could also do it with a date variable of course:

$myDate = '2011-04-05';
echo date('Y-m-d', strtotime($myDate . ' +1 Weekday'));

UPDATE: Or, if you have access to PHP's DateTime class (very likely):

$date = new DateTime('2018-01-27');
$date->modify('+7 weekday');
echo $date->format('Y-m-d');

Want to Skip Holidays?:

Although the original poster mentioned "I don't need to consider holidays", if you DO happen to want to ignore holidays, just remember - "Holidays" is just an array of whatever dates you don't want to include and differs by country, region, company, person...etc.

Simply put the above code into a function that excludes/loops past the dates you don't want included. Something like this:

$tmpDate = '2015-06-22';
$holidays = ['2015-07-04', '2015-10-31', '2015-12-25'];
$i = 1;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));

while (in_array($nextBusinessDay, $holidays)) {
    $i++;
    $nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
}

I'm sure the above code can be simplified or shortened if you want. I tried to write it in an easy-to-understand way.

Dave
  • 28,833
  • 23
  • 113
  • 183
  • @John Hunt - "holidays" is just an array of whatever dates you don't want to include and differs by country, region, company, person...etc. Simply put this into a function that excludes/loops past the dates you don't want included... it's quite easy to increment - just use `$i` instead of `1`. – Dave Feb 19 '13 at 15:31
  • 1
    @JohnHunt - btw, the OP had already mentioned "I dont need to consider holidays." prior to my answer (see his comment on middaparkas answer) – Dave Feb 19 '13 at 15:35
  • Here is a working example of how to exclude public/bank/national holidays: http://codepad.viper-7.com/NamlGN – MacroMan Nov 05 '14 at 11:31
  • Sorry to say that there is a known bug with strtotime with weekdays, if you do multiples of (+/-) 5 days it fails. https://bugs.php.net/bug.php?id=63521. So as a workaround I added an extra validation using date('w', strtotime( $nextBusinessDay )), to see if the date return is a Saturday or a Sunday, then adjust the date by 1 or 2 days. – Thanu Jul 06 '15 at 00:33
  • It helped me with minor modification. Thanks – Jarnail S Oct 30 '17 at 09:34
  • How could I rewrite this code in order to get the next workday including SATERDAY (just not sunday)? Thank you – Oliver Nov 03 '17 at 22:43
  • Thanks.. in order to make invariant to the holyday format, i modified in this way: $holies = []; foreach($holidays as $holiday){ $holies[]=strtotime($holiday); } while (in_array(strtotime($nextBusinessDay), $holies)) { $i++; $nextBusinessDay = date('d-m-Y', strtotime($tmpDate . ' +' . $i . ' Weekday')); } – ivandcl Jun 15 '19 at 13:49
9

For UK holidays you can use

https://www.gov.uk/bank-holidays#england-and-wales

The ICS format data is easy to parse. My suggestion is...

# $date must be in YYYY-MM-DD format
# You can pass in either an array of holidays in YYYYMMDD format
# OR a URL for a .ics file containing holidays
# this defaults to the UK government holiday data for England and Wales
function addBusinessDays($date,$numDays=1,$holidays='') {
    if ($holidays==='') $holidays = 'https://www.gov.uk/bank-holidays/england-and-wales.ics';

    if (!is_array($holidays)) {
        $ch = curl_init($holidays);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
        $ics = curl_exec($ch);
        curl_close($ch);
        $ics = explode("\n",$ics);
        $ics = preg_grep('/^DTSTART;/',$ics);
        $holidays = preg_replace('/^DTSTART;VALUE=DATE:(\\d{4})(\\d{2})(\\d{2}).*/s','$1-$2-$3',$ics);
    }

    $addDay = 0;
    while ($numDays--) {
        while (true) {
            $addDay++;
            $newDate = date('Y-m-d', strtotime("$date +$addDay Days"));
            $newDayOfWeek = date('w', strtotime($newDate));
            if ( $newDayOfWeek>0 && $newDayOfWeek<6 && !in_array($newDate,$holidays)) break;
        }
    }

    return $newDate;
}
user2412642
  • 151
  • 2
  • 1
2

This function will calculate the business day in the future or past. Arguments are number of days, forward (1) or backwards(0), and a date. If no date is supplied todays date will be used:

// returned $date Y/m/d
function work_days_from_date($days, $forward, $date=NULL) 
{
    if(!$date)
    {
        $date = date('Y-m-d'); // if no date given, use todays date
    }

    while ($days != 0) 
    {
        $forward == 1 ? $day = strtotime($date.' +1 day') : $day = strtotime($date.' -1 day');
        $date = date('Y-m-d',$day);
        if( date('N', strtotime($date)) <= 5) // if it's a weekday
        {
          $days--;
        }
    }
    return $date;
}
Angus
  • 141
  • 1
  • 2
  • 13
2
function next_business_day($date) {
  $add_day = 0;
  do {
    $add_day++;
    $new_date = date('Y-m-d', strtotime("$date +$add_day Days"));
    $new_day_of_week = date('w', strtotime($new_date));
  } while($new_day_of_week == 6 || $new_day_of_week == 0);

  return $new_date;
}

This function should ignore weekends (6 = Saturday and 0 = Sunday).

mhitza
  • 5,709
  • 2
  • 29
  • 52
1

I stumbled apon this thread when I was working on a Danish website where I needed to code a "Next day delivery" PHP script.

Here is what I came up with (This will display the name of the next working day in Danish, and the next working + 1 if current time is more than a given limit)

$day["Mon"] = "Mandag"; 
$day["Tue"] = "Tirsdag";
$day["Wed"] = "Onsdag";
$day["Thu"] = "Torsdag";
$day["Fri"] = "Fredag";
$day["Sat"] = "Lørdag";
$day["Sun"] = "Søndag";

date_default_timezone_set('Europe/Copenhagen');

$date = date('l');
$checkTime = '1400';
$date2 = date(strtotime($date.' +1 Weekday'));
if( date( 'Hi' ) >= $checkTime) {
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Saturday'){
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Sunday') {
$date2 = date(strtotime($date.' +2 Weekday'));
}
echo '<p>Næste levering: <span>'.$day[date("D", $date2)].'</span></p>';

As you can see in the sample code $checkTime is where I set the time limit which determines if the next day delivery will be +1 working day or +2 working days.

'1400' = 14:00 hours

I know that the if statements can be made more compressed, but I show my code for people to easily understand the way it works.

I hope someone out there can use this little snippet.

GeniusDesign
  • 499
  • 7
  • 25
1

What you need to do is:

  1. Convert the provided date into a timestamp.

  2. Use this along with the or w or N formatters for PHP's date command to tell you what day of the week it is.

  3. If it isn't a "business day", you can then increment the timestamp by a day (86400 seconds) and check again until you hit a business day.

N.B.: For this is really work, you'd also need to exclude any bank or public holidays, etc.

John Parker
  • 54,048
  • 11
  • 129
  • 129
1

Here is the best way to get business days (Mon-Fri) in PHP.

function days()
{
    $week=array();
    $weekday=["Monday","Tuesday","Wednesday","Thursday","Friday"];

    foreach ($weekday as $key => $value) 
    {
        $sort=$value." this week";
        $day=date('D', strtotime($sort)); 
        $date=date('d', strtotime($sort)); 
        $year=date('Y-m-d', strtotime($sort)); 

        $weeks['day']= $day;
        $weeks['date']= $date;
        $weeks['year']= $year;

        $week[]=$weeks;
    } 
    
    return $week;
}

Hope this will help you guys. Thanks,.

Rohit Agrohia
  • 368
  • 3
  • 7
0

See the example below:

$startDate = new DateTime( '2013-04-01' );    //intialize start date
$endDate = new DateTime( '2013-04-30' );    //initialize end date
$holiday = array('2013-04-11','2013-04-25');  //this is assumed list of holiday
$interval = new DateInterval('P1D');    // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);

For more info: http://goo.gl/YOsfPX

Suresh Kamrushi
  • 15,627
  • 13
  • 75
  • 90
0

You could do something like this.

/**
 * @param string $date
 * @param DateTimeZone|null|null $DateTimeZone
 * @return \NavigableDate\NavigableDateInterface
 */
function getNextBusinessDay(string $date, ? DateTimeZone $DateTimeZone = null):\NavigableDate\NavigableDateInterface
{
    $Date = \NavigableDate\NavigableDateFacade::create($date, $DateTimeZone);

    $NextDay = $Date->nextDay();
    while(true)
    {
        $nextDayIndexInTheWeek = (int) $NextDay->format('N');

        // check if the day is between Monday and Friday. In DateTime class php, Monday is 1 and Friday is 5
        if ($nextDayIndexInTheWeek >= 1 && $nextDayIndexInTheWeek <= 5)
        {
            break;
        }
        $NextDay = $NextDay->nextDay();
    }

    return $NextDay;
}

$date = '2017-02-24';
$NextBussinessDay = getNextBusinessDay($date);

var_dump($NextBussinessDay->format('Y-m-d'));

Output:

string(10) "2017-02-27"

\NavigableDate\NavigableDateFacade::create($date, $DateTimeZone), is provided by php library available at https://packagist.org/packages/ishworkh/navigable-date. You need to first include this library in your project with composer or direct download.

-1

I used below methods in PHP, strtotime() does not work specially in leap year February month.

public static function nextWorkingDay($date, $addDays = 1)
{
    if (strlen(trim($date)) <= 10) {
        $date = trim($date)." 09:00:00";
    }

    $date = new DateTime($date);
    //Add days
    $date->add(new DateInterval('P'.$addDays.'D'));

    while ($date->format('N') >= 5)
    {
        $date->add(new DateInterval('P1D'));
    }

    return $date->format('Y-m-d H:i:s');
}

This solution for 5 working days (you can change if you required for 6 or 4 days working). if you want to exclude more days like holidays then just check another condition in while loop.

//
while ($date->format('N') >= 5 && !in_array($date->format('Y-m-d'), self::holidayArray()))
Nishant Bhatt
  • 509
  • 5
  • 8
  • Are you sure about this? What about countries where non-business days are not defined by being on saturday and sunday? What about bank holidays? – Nico Haase Mar 13 '20 at 14:43
  • generally week days start from Monday or Sunday, that user can set from PHP. apart from that bank holidays and all that you have to mention from $holidayArray. as per your comment if some where its 4 working days then user can change 4 instead of 5 or 6. in while loop – Nishant Bhatt Mar 13 '20 at 15:05