Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate business days

Tags:

date

php

calendar

I need a method for adding "business days" in PHP. For example, Friday 12/5 + 3 business days = Wednesday 12/10.

At a minimum I need the code to understand weekends, but ideally it should account for US federal holidays as well. I'm sure I could come up with a solution by brute force if necessary, but I'm hoping there's a more elegant approach out there. Anyone?

Thanks.

like image 756
AdamTheHutt Avatar asked Dec 03 '08 03:12

AdamTheHutt


2 Answers

Here's a function from the user comments on the date() function page in the PHP manual. It's an improvement of an earlier function in the comments that adds support for leap years.

Enter the starting and ending dates, along with an array of any holidays that might be in between, and it returns the working days as an integer:

<?php //The function returns the no. of business days between two dates and it skips the holidays function getWorkingDays($startDate,$endDate,$holidays){     // do strtotime calculations just once     $endDate = strtotime($endDate);     $startDate = strtotime($startDate);       //The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24     //We add one to inlude both dates in the interval.     $days = ($endDate - $startDate) / 86400 + 1;      $no_full_weeks = floor($days / 7);     $no_remaining_days = fmod($days, 7);      //It will return 1 if it's Monday,.. ,7 for Sunday     $the_first_day_of_week = date("N", $startDate);     $the_last_day_of_week = date("N", $endDate);      //---->The two can be equal in leap years when february has 29 days, the equal sign is added here     //In the first case the whole interval is within a week, in the second case the interval falls in two weeks.     if ($the_first_day_of_week <= $the_last_day_of_week) {         if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;         if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;     }     else {         // (edit by Tokes to fix an edge case where the start day was a Sunday         // and the end day was NOT a Saturday)          // the day of the week for start is later than the day of the week for end         if ($the_first_day_of_week == 7) {             // if the start date is a Sunday, then we definitely subtract 1 day             $no_remaining_days--;              if ($the_last_day_of_week == 6) {                 // if the end date is a Saturday, then we subtract another day                 $no_remaining_days--;             }         }         else {             // the start date was a Saturday (or earlier), and the end date was (Mon..Fri)             // so we skip an entire weekend and subtract 2 days             $no_remaining_days -= 2;         }     }      //The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder //---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it    $workingDays = $no_full_weeks * 5;     if ($no_remaining_days > 0 )     {       $workingDays += $no_remaining_days;     }      //We subtract the holidays     foreach($holidays as $holiday){         $time_stamp=strtotime($holiday);         //If the holiday doesn't fall in weekend         if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)             $workingDays--;     }      return $workingDays; }  //Example:  $holidays=array("2008-12-25","2008-12-26","2009-01-01");  echo getWorkingDays("2008-12-22","2009-01-02",$holidays) // => will return 7 ?> 
like image 135
flamingLogos Avatar answered Sep 17 '22 13:09

flamingLogos


Get the number of working days without holidays between two dates :

Use example:

echo number_of_working_days('2013-12-23', '2013-12-29'); 

Output:

3 

Function:

function number_of_working_days($from, $to) {     $workingDays = [1, 2, 3, 4, 5]; # date format = N (1 = Monday, ...)     $holidayDays = ['*-12-25', '*-01-01', '2013-12-23']; # variable and fixed holidays      $from = new DateTime($from);     $to = new DateTime($to);     $to->modify('+1 day');     $interval = new DateInterval('P1D');     $periods = new DatePeriod($from, $interval, $to);      $days = 0;     foreach ($periods as $period) {         if (!in_array($period->format('N'), $workingDays)) continue;         if (in_array($period->format('Y-m-d'), $holidayDays)) continue;         if (in_array($period->format('*-m-d'), $holidayDays)) continue;         $days++;     }     return $days; } 
like image 45
Glavić Avatar answered Sep 20 '22 13:09

Glavić