I've a case where i need to figure a formula to calculate total time between date range sets (from->to) that can overlap each other. This is going to be used in a ticketing system where i need to calculate the total open time of all tickets (as part of an SLA agreement) without double calculating time that has been already counted. For example, in the records below:
TicketID | Open Date | Close Date |
---|---|---|
Ticket 1 | '2023-01-02 09:00:00' | '2023-01-02 14:00:00' |
Ticket 2 | '2023-01-02 11:00:00' | '2023-01-02 15:00:00' |
Ticket 3 | '2023-01-14 10:00:00' | '2023-01-14 11:00:00' |
the total time i would need to have is: from '2023-01-02 09:00:00' to '2023-01-02 15:00:00' and from '2023-01-14 10:00:00' to '2023-01-02 11:00:00', thus a total of 7 hours.
An ideas on where to start?
I've search for similar questions, such as this one PHP Determine when multiple(n) datetime ranges overlap each other but it is somewhat different than the one i need to have.
CodePudding user response:
The following solution first compresses all overlapping intervals into one using the reduceOverlap function. This means that intervals are then available which do not overlap. These are then added using the diffTotal function. As a result, a DateInterval object is available that can be formatted as you wish with the Format method.
<?php
function reduceOverlap(array $arr){
$flag = true;
while($flag){
$flag = false;
foreach($arr as $key1 => $row1){
foreach($arr as $key2 => $row2){
if($key1 === $key2) continue;
if(($row1['open'] >= $row2['open'] && $row1['open'] <= $row2['close']) OR
($row1['close'] >= $row2['open'] && $row1['close'] <= $row2['close'])){
$arr[$key1]['open'] = min($row1['open'],$row2['open']);
$arr[$key1]['close'] = max($row1['close'],$row2['close']);
unset($arr[$key2]);
$flag = true;
break 2;
}
}
}
}
return $arr;
}
function diffTotal(array $arr){
$date = date_create('1970-01-01 00:00');
foreach($arr as $row){
$diff = date_create($row['open'])->diff(date_create($row['close']));
$date->add($diff);
}
return date_create('1970-01-01 00:00')->diff($date);
}
$times = [
['open' => '2023-01-02 09:00:00', 'close' => '2023-01-02 14:00:00'],
['open' => '2023-01-02 11:00:00', 'close' => '2023-01-02 15:00:00'],
['open' => '2023-01-14 10:00:00', 'close' => '2023-01-14 11:00:00'],
];
$arr = reduceOverlap($times);
$diffTotal = diffTotal($arr);
var_dump($diffTotal);
Output:
object(DateInterval)#2 (10) {
["y"]=>
int(0)
["m"]=>
int(0)
["d"]=>
int(0)
["h"]=>
int(7)
["i"]=>
int(0)
["s"]=>
int(0)
["f"]=>
float(0)
["invert"]=>
int(0)
["days"]=>
int(0)
["from_string"]=>
bool(false)
}
try self: https://3v4l.org/MPNPC