Calculate future date based on business days I've written a program for calculating the future date after certain number of business days.

function add_business_days($startdate,$businessdays,$holidays,$dateformat){  
   $i=1;  
   $dayx = strtotime($startdate);  

  while($i &lt; $businessdays){  
     $day = date('N',$dayx);  
     $date = date('Y-m-d',$dayx);  
     if($day &lt; 6 &amp;&amp; !in_array($date,$holidays))$i++;  
     $dayx = strtotime($date.' +1 day');  
  }  
  return date($dateformat,$dayx);
}


But the problem with this function is that it doesn't check the last date of business day for Saturday and Sunday. Also, the last day could be the holiday. Can anyone provide me a better solution for this?



I've made a solution to this problem as

function add_business_days($startdate,$businessdays,$holidays,$dateformat){  
   $i=1;  
   $dayx = strtotime($startdate);  

  while($i &lt;= $businessdays){  
     $day = date('N',$dayx);  
     $date = date('Y-m-d',$dayx);  
     if($day &lt; 6 &amp;&amp; !in_array($date,$holidays))$i++;  
     $dayx = strtotime($date.' +1 day');  
  }  
  return date($dateformat,strtotime(date('Y-m-d', $dayx) . ' -1 day'));
}


But it doesn't seems good.



Usage Example

I'm using this method for calculating the shipment date on which a product will be delivered to the customer.

$startdate = "2014-05-28";  //Order placing date  
$businessdays = 7; //number of days for delivery  
$holidays = array('2014-05-30','2014-06-03');  //array of dates having holidays. excluding business days.  
$dateformat = 'd-m-Y';  //output date format for displaying.
$delivery = add_business_days($startdate, $businessdays, $holidays, $dateformat);


The $delivery is supposed to have date 09-06-2014 but the first code returns 07-06-2014 which doesn't check for the last date in loop for weekends (Saturday or Sunday). I've made the solution in the second program by execution the loop one more time and then return the previous date. But this approach doesn't seem good. Any suggestions on not going over and returning the previous date?
I propose a class, BusinessDayCalculator, which would handle all this logic in one place. Here's an example:

&lt;?php

class BusinessDaysCalculator {

    const MONDAY    = 1;
    const TUESDAY   = 2;
    const WEDNESDAY = 3;
    const THURSDAY  = 4;
    const FRIDAY    = 5;
    const SATURDAY  = 6;
    const SUNDAY    = 7;

    /**
     * @param DateTime   $startDate       Date to start calculations from
     * @param DateTime[] $holidays        Array of holidays, holidays are no conisdered business days.
     * @param int[]      $nonBusinessDays Array of days of the week which are not business days.
     */
    public function __construct(DateTime $startDate, array $holidays, array $nonBusinessDays) {
        $this-&gt;date = $startDate;
        $this-&gt;holidays = $holidays;
        $this-&gt;nonBusinessDays = $nonBusinessDays;
    }

    public function addBusinessDays($howManyDays) {
        $i = 0;
        while ($i &lt; $howManyDays) {
            $this-&gt;date-&gt;modify("+1 day");
            if ($this-&gt;isBusinessDay($this-&gt;date)) {
                $i++;
            }
        }
    }

    public function getDate() {
        return $this-&gt;date;
    }

    private function isBusinessDay(DateTime $date) {
        if (in_array((int)$date-&gt;format('N'), $this-&gt;nonBusinessDays)) {
            return false; //Date is a nonBusinessDay.
        }
        foreach ($this-&gt;holidays as $day) {
            if ($date-&gt;format('Y-m-d') == $day-&gt;format('Y-m-d')) {
                return false; //Date is a holiday.
            }
        }
        return true; //Date is a business day.
    }
}

$calculator = new BusinessDaysCalculator(
    new DateTime(), // Today
    [new DateTime("2014-06-01"), new DateTime("2014-06-02")],
    [BusinessDaysCalculator::SATURDAY, BusinessDaysCalculator::FRIDAY]
);

$calculator-&gt;addBusinessDays(3); // Add three business days 

var_dump($calculator-&gt;getDate());


In the above example the nonBusinessDays of the week are SATURDAY and FRIDAY, and 1st and 2nd of June are holidays. In that case, 3 business days from now is June 5th.

This can probably be improved further, let your imagination run wild :P