简体   繁体   English

计算重叠日期范围之间的时间

[英]Calculate time between overlapping date ranges

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.这将用于票务系统,在该系统中我需要计算所有票证的总开放时间(作为 SLA 协议的一部分),而无需重复计算已经计算的时间。 For example, in the records below:例如,在下面的记录中:

TicketID票号 Open Date开放日期 Close Date截止日期
Ticket 1机票 1 '2023-01-02 09:00:00' '2023-01-02 09:00:00' '2023-01-02 14:00:00' '2023-01-02 14:00:00'
Ticket 2门票 2 '2023-01-02 11:00:00' '2023-01-02 11:00:00' '2023-01-02 15:00:00' '2023-01-02 15:00:00'
Ticket 3门票 3 '2023-01-14 10:00:00' '2023-01-14 10:00:00' '2023-01-14 11: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.我需要的总时间是:从“2023-01-02 09:00:00”到“2023-01-02 15:00:00”和“2023-01-14 10:00:00”到 '2023-01-02 11:00:00',因此总共 7 小时。

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.我已经搜索过类似的问题,例如这个PHP Determine when multiple(n) datetime ranges overlap each other但它与我需要的有所不同。

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.以下解决方案首先使用 reduceOverlap function 将所有重叠间隔压缩为一个。这意味着随后可以使用不重叠的间隔。 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.然后使用 diffTotal function 添加这些。因此,可以使用 Format 方法根据需要格式化 DateInterval object。

<?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: 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尝试自我: https://3v4l.org/MPNPC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM