Calculate Business Hours between two dates
Moderator: General Moderators
Calculate Business Hours between two dates
Does anyone have a script or know where I can get a script to calculate business hours between two dates excluding holidays. I can probably create one myself but it would probably takes forever. 
Once I had to calculate business days between two dates, here's what I came to:
Code: Select all
/**
Number of seconds in a day
**/
define("DAYSECONDS", 60 * 60 * 24);
/**
counts holidays falling into the given range
@param $left integer leftmost end-point of the interval (unix timestamp)
@param $right integer rightmost end-point of the interval (unix timestamp)
@return integer count of holidays falling into the given range
**/
function count_weekend_days($left, $right) {
if($right < $left) return false;
$firstmonday = strtotime("monday", $left);
$lastmonday = strtotime("last monday", $right);
$weeks_between = floor( ($lastmonday - $firstmonday) / (DAYSECONDS * 7) );
$first_weekend = ceil( ($firstmonday - $left) / DAYSECONDS );
$first_weekend = ($first_weekend < 2 ? $first_weekend : 2);
$last_weekend = floor( ( strtotime("next monday", $lastmonday) - $right ) / DAYSECONDS );
$last_weekend = ( (2 - $last_weekend) > 0 ? ( 2 - $last_weekend) : 0);
return $first_weekend + 2 * $weeks_between + $last_weekend;
}
/**
counts weekdays falling into the given range
@param $left integer leftmost end-point of the interval (unix timestamp)
@param $right integer rightmost end-point of the interval (unix timestamp)
@return integer count of weekdays falling into the given range
**/
function count_working_days($left, $right) {
if($right < $left) return false;
return floor( ($right - $left) / DAYSECONDS ) - count_weekend_days($left, $right);
}Untested, but this might work:
This will also work when a day doesn't have 60 * 60 * 24 seconds (switching in and out of daylight saving time)
Code: Select all
//set up holidays. There may be a built in PHP function, but I don't know it.
$holidays[] = '24.12.2005';
$holidays[] = '25.12.2005';
$date1 = "1100674800";
$date2 = "1132243341";
$running_date = $date1;
$business_hours_per_day = 8;
$total_hours = 0;
do
{
$day_number = date('w',$running_date);
//only consider weekdays
if($day_number != 0 && $day_number != 6)
{
//check if day is a holiday
if(!in_array(date('j.m.Y',$running_date),$holidays)
{
$total_hours += $business_hours_per_day;
}
}
$running_date = strototime('+1 day',$running_date);
}
while($running_date <= $date2);Real programmers don't comment their code. If it was hard to write, it should be hard to understand.
Mine works as wellpickle wrote:This will also work when a day doesn't have 60 * 60 * 24 seconds (switching in and out of daylight saving time)
There's another pitfall in your algorithm: its execution time is in linear proportion to the difference between last_date and first_date, while mine has constant execution time.
Thanks for the tips guys, I tested both versions and here what I came up with.
begin date 1131026473 = 11/03/2005 9:01 am Thu
end date 1131390020 = 11/07/2005 2:00 pm Mon
Weirdan version
1 days
Pickle version
24 hours
I need it to calculate 9:01 - 6:00pm = 8hr on Thu
9:00 - 6:00pm = 8hr on Fri
9:00 - 2:00pm = 5hr on Mon
total = 21 hrs
Code: Select all
$date1 = 1131026473;
$date2 = 1131390020;
echo "begin date ".$date1." = ";echo date('m/d/Y g:i a D',$date1)."<br>";
echo "end date ".$date2." = ";echo date('m/d/Y g:i a D',$date2)."<br>";
echo "Weirdan version <br>";
echo count_working_days($date1,$date2)." days";
echo "<br>";
echo "Pickle version<br>";
echo count_working_days2($date1,$date2)." hours";end date 1131390020 = 11/07/2005 2:00 pm Mon
Weirdan version
1 days
Pickle version
24 hours
I need it to calculate 9:01 - 6:00pm = 8hr on Thu
9:00 - 6:00pm = 8hr on Fri
9:00 - 2:00pm = 5hr on Mon
total = 21 hrs
Tack this on the end of mine:
Again this is untested. What this does is add the difference (positive or negative) between the calculated end date and the actual end date.
Code: Select all
$running_total += (($running_date - $date2) * 60 * 60);Again this is untested. What this does is add the difference (positive or negative) between the calculated end date and the actual end date.
Real programmers don't comment their code. If it was hard to write, it should be hard to understand.
I would do something like below, because then you can base exact hours on each day and also include holidays that may or may or may not be working holidays! You could also easily add different work weeks with different hours but that would be another example!
yj
Code: Select all
<?
// the starting date
$start_date = '11-17-2005';
// the ending date
$end_date = '11-20-2005';
// the daily hours in a week! sunday to saturday
$work_hours = array ( 0, 8, 8, 8, 8, 8, 0 );
// an array of holidays (key = date, value = hours of work for that holiday)
$holidays = array ( '11-24-2005' => 4, '12-25-2005' => 0 );
echo hours_till ( $start_date, $end_date, $work_hours, $holidays );
function hours_till ( $s, $e, $w, $h )
{
$r = array ();
$s = mktime ( 0, 0, 0, substr ( $s, 0, 2 ), substr ( $s, 3, 2 ), substr ( $s, 6, 4 ) );
$e = mktime ( 0, 0, 0, substr ( $e, 0, 2 ), substr ( $e, 3, 2 ), substr ( $e, 6, 4 ) );
if ( is_array ( $h ) )
{
foreach ( $h AS $hn => $hv )
{
$temp = mktime ( 0, 0, 0, substr ( $hn, 0, 2 ), substr ( $hn, 3, 2 ), substr ( $hn, 6, 4 ) );
if ( $temp >= $s && $temp <= $e )
{
$r[$temp] = $hv;
}
}
}
$th = 0;
$ns = date ( 'w', $s );
for ( $x = $s; $x <= $e; $x += 86400 )
{
$f = true;
foreach ( $r AS $hn => $hv )
{
if ( $x == $hn )
{
$f = false;
$th += $hv;
unset ( $r[$hn] );
break;
}
}
if ( $f )
{
$th += $w[$ns];
}
$ns = ( $ns == 6 ? 0 : ++$ns );
}
return ( $th );
}
?>yj
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA