Calculate the number of working day hours between two dates

I need to calculate the number of working hours that have expired between two dates. Working hours are 08:30 to 17:30, Monday to Friday.

Here is what I have so far, can anybody see the flaws in my logic? I’m sure it could also be made much more compact and better.


 /*You take your start date and calculate the rest time on this day (if it is a business day)
 You take your end date and calculate the time on this day and
 take the days in between and multiply them with your business hours (just those,   that are business days)
 Day start is 08:30 and day end is 17:30 so 9 hour working days*/

function biss_hours($start, $end){

   $startDate = new DateTime($start);
   $endDate = new DateTime($end);

   //Set the start and end dates to the start of the working day
   $startofday = clone $startDate;
   $startofday->setTime(8,30);
   $enddaystart = clone $endDate;
   $enddaystart->setTime(8,30);

   //get the rest time on start day in hours
   $t1 = $startofday->format('Y-m-d H:i:s');
   $t2 = $startDate->format('Y-m-d H:i:s');
   $firstDayRest = calculate_hours($t1, $t2);

   //get the rest time on start day in hours
   $t3 = $enddaystart->format('Y-m-d H:i:s');
   $t4 = $endDate->format('Y-m-d H:i:s');
   $lastDayRest = calculate_hours($t3, $t4);

   //Get the number of days between the two dates
   $daysBetween = getWeekdayDifference($start, $end);
   //multiply the days by the 9 working hours
   $hoursBetween = $daysBetween * 9;
   //add the rest times onto the number of working hours between the two dates.
   return $hoursBetween + $firstDayRest + $lastDayRest;

}


//returns the hours between two dates
function calculate_hours($t1, $t2){
   $t1 = StrToTime ($t1);
   $t2 = StrToTime ($t2);

   $diff = $t2 - $t1;
   $hours = $diff / ( 60 * 60 );

   return $hours;
}
//returns the number of days (excluding weekends) between two dates
function getWeekdayDifference($startDate, $endDate)
{
   $days = 0;

   $startDate = new DateTime($startDate);
   $endDate = new DateTime($endDate);

   while($startDate->diff($endDate)->days > 0) {
      $days += $startDate->format('N') < 6 ? 1 : 0;
      $startDate = $startDate->add(new \\DateInterval("P1D"));
   }

   return $days;
}

$start = '2014-06-25 11:30';
$end = '2014-07-22 12:30';
echo $onHold = biss_hours($start, $end);



Iv came up with this kinda neat solution but its only to the nearest hour rather than min, but id prefer down to be more exact.


function biss_hours($start, $end){

    $startDate = new DateTime($start);
    $endDate = new DateTime($end);
    $periodInterval = new DateInterval( "PT1H" );

    $period = new DatePeriod( $startDate, $periodInterval, $endDate );
    $count = 0;

    foreach($period as $date){

    $startofday = clone $date;
    $startofday->setTime(8,30);

    $endofday = clone $date;
    $endofday->setTime(17,30);

        if($date > $startofday && $date <= $endofday && !in_array($date->format('l'), array('Sunday','Saturday'))){

            $count++;
        }

    }
    echo $count;
}

$start = '2014-06-23 12:30:00';
$end = '2014-06-27 15:45:00';

$go = biss_hours($start,$end);

Ment to say need help getting it to the exact minute.

In POST#2 can you get just the minutes and seconds from both dates in seconds?

Then after your foreach statement subtract the base time for the day to get the difference.
Anyway, this is what I came up with.

<?php

function biss_hours($start, $end){

    $startDate = new DateTime($start);
    $endDate = new DateTime($end);
    $periodInterval = new DateInterval( "PT1H" );

    $period = new DatePeriod( $startDate, $periodInterval, $endDate );
    $count = 0;

    foreach($period as $date){

    $startofday = clone $date;
    $startofday->setTime(8,30);

    $endofday = clone $date;
    $endofday->setTime(17,30);

        if($date > $startofday && $date <= $endofday && !in_array($date->format('l'), array('Sunday','Saturday'))){

            $count++;
        }

    }
	
	//Get seconds of Start time
	$start_d = date("Y-m-d H:00:00", strtotime($start));
	$start_d_seconds = strtotime($start_d);
	$start_t_seconds = strtotime($start);
	$start_seconds = $start_t_seconds - $start_d_seconds;
							
	//Get seconds of End time
	$end_d = date("Y-m-d H:00:00", strtotime($end));
	$end_d_seconds = strtotime($end_d);
	$end_t_seconds = strtotime($end);
	$end_seconds = $end_t_seconds - $end_d_seconds;
									
	$diff = $end_seconds-$start_seconds;
	
	if($diff!=0):
		$count--;
	endif;
		
	$total_min_sec = date('i:s',$diff);
	
	return $count .":".$total_min_sec;
}

$start = '2014-06-23 12:30:00';
$end = '2014-06-27 15:45:00';

$go = biss_hours($start,$end);
echo $go;
?>

Seems good, testing it now.

Both seem to be working fine for my purposes s far. Thanks for the help.