Algorithm outline:
- Order you intervals by starting time.
- Go through them and join neighbors that intersect. The intersection condition will be that the second interval's start time is before or equal to the first interval's end time. Because of the ordering only one loop will be needed.
- At this point you have only disjoint intervals and you can sum their spans to get the total span.
And here is an implementation of that algorithm:
<?php
// assuming hh:mm format for all the dates //
$intervals = array(
array(
'start' => '15:30',
'end' => '16:00',
),
array(
'start' => '10:00',
'end' => '13:00',
),
array(
'start' => '15:00',
'end' => '16:09',
),
array(
'start' => '11:00',
'end' => '14:00',
),
);
// 1. sort the intervals by start date //
function mySortIntervals($a, $b){
return $a > $b;
}
usort($intervals, 'mySortIntervals');
// 2. merge adjoining intervals //
$active = 0;
$current = 1;
$length = count($intervals);
while($current < $length){
if($intervals[ $current ]['start'] <= $intervals[ $active ]['end']){
$intervals[ $active ]['end'] = max($intervals[ $active ]['end'], $intervals[ $current ]['end']);
unset($intervals[ $current ]);
}
else{
$active = $current;
}
$current++;
}
// 3. cout the total time //
$time = 0;
foreach($intervals as $interval){
$time += strtotime($interval['end']) - strtotime($interval['start']);
}
// output //
echo str_pad((int) ($time/60/60), 2, '0', STR_PAD_LEFT).':';
echo str_pad((int) (($time/60)%60), 2, '0', STR_PAD_LEFT);
?>