title: Calculate Working Days in PHP - Doesn't work for months where the 12th is on Monday
body: <p>I have the strangest issue. I have a script that calculates what the current work day is in a month along with the total amount of working days for the month. For example, today June 25, the script would output "day 17/21".</p>
  
  <p>The strange thing is, for months where the 12th falls on a monday, from the 12th till the end of the month, the current work day shows as 0.0417 days less than what it actually is. For example, for March 11th (a sunday) it shows "7/22". But for March 12th, it shows "7.95833333/22"</p>
  
  <p>Below is my code for the script which I had found on a post somewhere on the internet. Every other time it works perfectly except for this odd occasion. </p>
  
  <pre><code>//##########################################################
  //Date Calculations
  //##########################################################
  
      $datepicker = $_POST['datepicker'];
      $dpyear = date("Y", strtotime($datepicker));
      $dpmonth = date("m", strtotime($datepicker));
      $dpday = date("d", strtotime($datepicker));
  
          $end = date('Y/m/d', mktime(0, 0, 0, $dpmonth, $dpday, $dpyear));       // seconds * minutes * hours * days
          $first = date('Y/m/d', mktime(0, 0, 0, $dpmonth, 1, $dpyear));
          $firstOfYear = date('Y/m/d', mktime(0, 0, 0, 1, 1, $dpyear));
          $last = date('Y/m/d', mktime(0, 0, 0, $dpmonth + 1, 0, $dpyear));
          $firstprevyear = date('Y/m/d', mktime(0, 0, 0, $dpmonth, 1, $dpyear-1));
          $lastprevyear = date('Y/m/d', mktime(0, 0, 0, $dpmonth + 1, 0, $dpyear-1));
          $prevyearmonth = date('M\'y', mktime(0, 0, 0, $dpmonth + 1, 0, $dpyear-1));
  
          $prevyeardate = "sojd.InvoiceDate &gt;= '$firstprevyear' and sojd.InvoiceDate &lt;= '$lastprevyear' ";
          $mtddaterange = "sojd.InvoiceDate &gt;= '$first' and sojd.InvoiceDate &lt;= '$end' ";
          $ytddaterange = "sojd.InvoiceDate &gt;= '$firstOfYear' and sojd.InvoiceDate &lt;= '$end' ";
  
  
  
          if (date("w", strtotime($datepicker)) == 1) {       // if today is Monday, combine weekend and Monday's numbers
              $startDate = date('Y/m/d', mktime(0, 0, 0, $dpmonth, $dpday - 2, $dpyear));
              $prevdaterange = "sojd.InvoiceDate &gt;= '$startDate' and sojd.InvoiceDate &lt;= '$end'";
              $daterange = "sojd.InvoiceDate &gt;= '$startDate' and sojd.InvoiceDate &lt;= '$end'";
              $params = array($startDate, $end);
          } else {
              $prevdaterange = "sojd.InvoiceDate = '$end' ";
              $daterange = "sojd.InvoiceDate = '$end'";
              $params = array($end);
          }
  
  
  
      $holidays=array("2012-01-02","2012-05-28","2012-07-04","2012-09-03","2012-11-22","2012-12-25");
  
  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);
  
      //----&gt;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 &lt;= $the_last_day_of_week) {
          if ($the_first_day_of_week &lt;= 6 &amp;&amp; 6 &lt;= $the_last_day_of_week) $no_remaining_days--;
          if ($the_first_day_of_week &lt;= 7 &amp;&amp; 7 &lt;= $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
  //----&gt;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 &gt; 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 &lt;= $time_stamp &amp;&amp; $time_stamp &lt;= $endDate &amp;&amp; date("N",$time_stamp) != 6 &amp;&amp; date("N",$time_stamp) != 7)
              $workingDays--;
      }
  
      return $workingDays;
  }
      $currSalesDay = getWorkingDays($first,$end,$holidays);
      $totalSalesDay = round(getWorkingDays($first,$last,$holidays),0);
  </code></pre>