简体   繁体   English

如何检查 PHP 中多个日期范围之间的重叠?

[英]How to check overlapping among multiple date ranges in PHP?

There are many posts about checking overlapping between two dates.有很多关于检查两个日期之间重叠的帖子。 However I couldn't find any which talks about how to check among multple ranges.但是我找不到任何关于如何在多个范围之间进行检查的内容。

Say I have this array:假设我有这个数组:

$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')]

One may simply think that a function which checks overlapping between two ranges can work with a loop among all ranges, but this is wrong, because all ranges can overlap with each others, but not overlap all together.人们可能会简单地认为,检查两个范围之间的重叠的 function 可以与所有范围之间的循环一起工作,但这是错误的,因为所有范围可以相互重叠,但不能重叠在一起。

I hope someone can help me to find a good solution.....我希望有人可以帮助我找到一个好的解决方案......

<?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));

None of the above solutions really worked for me, I am using Carbon API here for date comparison but this can be achieved by normal PHP date comparison if you are not using Carbon API.上述解决方案都不适用于我,我在这里使用 Carbon API 进行日期比较,但如果您不使用 Carbon API,则可以通过普通的 PHP 日期比较来实现。

PS: Happy if someone can optimize this code. 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;
}

based on Raeef Refai answer the algorithm only checks dates next to each other but not as a whole list of dateranges.根据 Raeef Refai 的回答,该算法只检查彼此相邻的日期,而不是检查整个日期范围列表。 here a tweaked version.这里是一个调整版本。 hope this helps.希望这可以帮助。

$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;
      }
    }
  }
}

I convert the Carbon answer of Reef in pure PHP我将 Reef 的碳答案转换为纯 PHP

function checkOverlapInDateRanges($ranges) {
    
    $overlapp = [];
    
    for($i = 0; $i < count($ranges); $i++){
        
        for($j= ($i + 1); $j < count($ranges); $j++){

            $start_a = strtotime($ranges[$i]['start']);
            $end_a = strtotime($ranges[$i]['end']);

            $start_b = strtotime($ranges[$j]['start']);
            $end_b = strtotime($ranges[$j]['end']);

            if( $start_b <= $end_a && $end_b >= $start_a ) {
                $overlapp[] = "i:$i j:$j " .$ranges[$i]['start'] ." - " .$ranges[$i]['end'] ." overlap with " .$ranges[$j]['start'] ." - " .$ranges[$j]['end'];
                break;
            }
            
        }
        
    }
    
    return $overlapp;
    
}

// example
$ranges = array(
    array('start' => '2022-01-01', 'end' => '2022-01-05'),
    array('start' => '2022-01-05', 'end' => '2022-01-10'),
    array('start' => '2022-01-9', 'end' => '2022-01-15'),
    array('start' => '2022-01-13', 'end' => '2022-01-15')
);

echo "<pre>";
var_dump(checkOverlapInDateRanges($ranges));
echo "</pre>";

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

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