Here's a code for you, a code which calculate the time and:
Does not not use any loops, which are very inefficient and not really needed.
It calculates the time by minutes to be able to handle accurately any hour, such as 14:27.
The code deals with the over midnight working hour times.
Returns a nice array with relevant data, which can be helpful for debugging.
the result is in ['total_in_minutes'] in minutes, but also in ['total_in_hours'] in hours .
Output:
Array
(
[total_in_hours] => 5
[total_in_minutes] => 300
[days] => 1
[is_over_midnight] => 1
[total_min_first_day] => 120
[total_min_middle_days] => 0
[total_min_last_day] => 180
)
Code:
$starttime="22:00";
$endtime="02:00";
$entrance="2016-06-24 20:00:00";
$exit="2016-06-25 05:00:00";
$time = calc_overtime($starttime, $endtime, $entrance, $exit);
print_r($time);
function calc_overtime($starttime, $endtime, $entrance, $exit){
$total_days = date("d", strtotime($exit)) - date("d", strtotime($entrance));
$working_hours[0] = array('start'=>get_minutes($starttime), 'end'=>get_minutes($endtime));
$working_hours_a_day = ($working_hours[0]['end']-$working_hours[0]['start']);
$over_midnight = (get_minutes($endtime)<get_minutes($starttime))?1:0;
// split into two working hours which end>start in both
if ($over_midnight) {
$working_hours[0] = array('start'=>get_minutes($starttime), 'end'=> 24*60);
$working_hours[1] = array('start'=>0, 'end'=>get_minutes($endtime));
$working_hours_a_day = ($working_hours[0]['end']-$working_hours[0]['start'])+($working_hours[1]['end']-$working_hours[1]['start']);
}
// only one day - came and left the same day
if ($total_days == 0){
$total_overtime = calc_overtime_one_day(get_minutes($exit)-get_minutes($entrance), get_minutes($entrance), get_minutes($exit), $working_hours[0]['start'], $working_hours[0]['end']);
$total_overtime = $over_midnight? calc_overtime_one_day($total_overtime, get_minutes($entrance), get_minutes($exit), $working_hours[1]['start'], $working_hours[1]['end']): $total_overtime;
return array('total_in_hours'=>$total_overtime/60 ,'total_in_minutes'=>$total_overtime , 'days' => $total_days, 'is_over_midnight'=>$over_midnight) ;
}
// More than one day
$total_overtime_first_day = calc_overtime_one_day(24*60-get_minutes($entrance), get_minutes($entrance), 24*60, $working_hours[0]['start'], $working_hours[0]['end']);
$total_overtime_first_day = $over_midnight ? calc_overtime_one_day($total_overtime_first_day, get_minutes($entrance), 24*60, $working_hours[1]['start'], $working_hours[1]['end']): $total_overtime_first_day;
$total_overtime_last_day = calc_overtime_one_day(get_minutes($exit)-0, 0, get_minutes($exit), $working_hours[0]['start'], $working_hours[0]['end']);
$total_overtime_last_day = $over_midnight ? calc_overtime_one_day($total_overtime_last_day, 0, get_minutes($exit), $working_hours[1]['start'], $working_hours[1]['end']):$total_overtime_last_day;
$total_middle_days = ($total_days>1)? ((24*60-$working_hours_a_day)*($total_days-1)):0;
$total = $total_overtime_first_day + $total_overtime_last_day + $total_middle_days;
return array('total_in_hours'=>$total/60 , 'total_in_minutes'=>$total ,
'days' => $total_days, 'is_over_midnight'=>$over_midnight, 'total_min_first_day'=>$total_overtime_first_day,
'total_min_middle_days'=>$total_middle_days, 'total_min_last_day'=>$total_overtime_last_day) ;
}
function calc_overtime_one_day($current_minutes, $entrance, $exit, $gap_start, $gap_end){
if ($entrance>=$gap_end || $exit <= $gap_start) { return $current_minutes; }
$remove_end = $gap_end;
$remove_start = $gap_start;
if ($entrance>=$gap_start) { $remove_start = $entrance; }
if ($exit<=$gap_end) {$remove_end = $exit;}
if ($exit<=$gap_end) {$remove_end = $exit;}
return $current_minutes - ($remove_end-$remove_start);
}
function get_minutes($string_time){
$timestamp = strtotime($string_time);
return 60*date("H", $timestamp)+1*date("i", $timestamp);
}