【问题标题】:How to check overlapping among multiple date ranges in PHP?如何检查 PHP 中多个日期范围之间的重叠?
【发布时间】:2014-03-14 03:05:54
【问题描述】:

有很多关于检查两个日期之间重叠的帖子。但是我找不到任何关于如何检查多个范围的内容。

假设我有这个数组:

$ranges = [
array('start'=>'2014-01-01' , 'end'=> '2014-01-05'),
array('start'=>'2014-01-06' > , 'end'=> '2014-01-10'),
array('start'=>'2014-01-04' > , 'end'=> '2014-01-07')]

人们可能会简单地认为检查两个范围之间的重叠的函数可以在所有范围之间循环工作,但这是错误的,因为所有范围可以相互重叠,但不能完全重叠。 em>

希望有人能帮我找到一个好的解决方案.....

【问题讨论】:

    标签: php algorithm date overlap overlapping


    【解决方案1】:
    <?php
    
    // pass your ranges to this method and if there is a common intersecion it will
    // return it or false
    
    function checkIfOverlapped($ranges)
    {
        $res = $ranges[0];
    
        $countRanges = count($ranges);
    
        for ($i = 1; $i < $countRanges; $i++) {
    
            $r1s = $res['start'];
            $r1e = $res['end'];
    
            $r2s = $ranges[$i]['start'];
            $r2e = $ranges[$i]['end'];
    
            if ($r1s >= $r2s && $r1s <= $r2e || $r1e >= $r2s && $r1e <= $r2e || $r2s >= $r1s && $r2s <= $r1e || $r2e >= $r1s && $r2e <= $r1e) {
    
                $res = array(
                    'start' => $r1s > $r2s ? $r1s : $r2s,
                    'end' => $r1e < $r2e ? $r1e : $r2e
                );
    
            } else return false;
    
        }
    
        return $res;
    }
    
    // example
    $ranges = array(
        array('start' => '2014-01-01', 'end' => '2014-01-05'),
        array('start' => '2014-01-05', 'end' => '2014-01-10'),
        array('start' => '2014-01-04', 'end' => '2014-01-07')
    );
    
    var_dump(checkIfOverlapped($ranges));
    

    【讨论】:

    • 如果在循环的第一次迭代中,没有重叠,函数将返回false,不再进行比较。
    • 这个函数是找一个共同的交集,所以如果前两个没有交集就是假的。
    • 感谢您的解释。我理解 OP 想知道 any 是否重叠与 all 是否重叠,但是重新阅读它,很难确定 OP 正在寻找哪种方案。
    【解决方案2】:

    上述解决方案都没有真正适合我,我在这里使用 Carbon API 进行日期比较,但如果您不使用 Carbon API,这可以通过普通的 PHP 日期比较来实现。

    PS:如果有人能优化这段代码,我很高兴。

    public static function checkOverlapInDateRanges($ranges) {
        $overlapp = [];
        for($i = 0; $i < count($ranges); $i++){
            for($j= ($i + 1); $j < count($ranges); $j++){
    
                $start = \Carbon\Carbon::parse($ranges[$j]['start']);
                $end = \Carbon\Carbon::parse($ranges[$j]['end']);
    
                $start_first = \Carbon\Carbon::parse($ranges[$i]['start']);
                $end_first = \Carbon\Carbon::parse($ranges[$i]['end']);
    
                if(\Carbon\Carbon::parse($ranges[$i]['start'])->between($start, $end) || \Carbon\Carbon::parse($ranges[$i]['end'])->between($start, $end)){
                    $overlapp[] = $ranges[$j];
                    break;
                }
                if(\Carbon\Carbon::parse($ranges[$j]['start'])->between($start_first, $end_first) || \Carbon\Carbon::parse($ranges[$j]['end'])->between($start_first, $end_first)){
                    $overlapp[] = $ranges[$j];
                    break;
                }
            }
        }
        return $overlapp;
    }
    

    【讨论】:

    • 用原生PHP代码替换“between”函数,可以使用if ($start_first &lt;= $end &amp;&amp; $end_first &gt;= $start) { // overlap }
    【解决方案3】:

    基于 Raeef Refai 的回答,该算法仅检查彼此相邻的日期,而不是整个日期范围列表。这是一个调整后的版本。希望这会有所帮助。

    $ranges = [
        ['2014-01-01','2014-01-05'],
        ['2014-01-05','2014-01-10'],
        ['2014-01-04','2014-01-07']
    ];
    
    foreach($ranges as $key => $range){
    
      $r1s = $range[0];
      $r1e = $range[1];
    
      foreach($ranges as $key2 => $range2){
        if($key != $key2){
          $r2s = $range2[0];
          $r2e = $range2[1];
    
          if ($r1s >= $r2s && $r1s <= $r2e || $r1e >= $r2s && $r1e <= $r2e || $r2s >= $r1s && $r2s <= $r1e || $r2e >= $r1s && $r2e <= $r1e) {
    
              $res = array(
                  '0' => $r1s > $r2s ? $r1s : $r2s,
                  '1' => $r1e < $r2e ? $r1e : $r2e
              );
              break;
          }
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-06-21
      • 1970-01-01
      • 2019-12-27
      • 2018-03-03
      • 1970-01-01
      • 2014-01-06
      • 1970-01-01
      • 2017-06-08
      • 2011-02-02
      相关资源
      最近更新 更多