Как проверить перекрытие между несколькими диапазонами дат в PHP?

Есть много сообщений о проверке совпадения между двумя датами. Однако я не смог найти ни одного, в котором говорилось бы о том, как проверять несколько диапазонов.

Скажем, у меня есть этот массив:

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

Можно просто подумать, что функция, проверяющая перекрытие между двумя диапазонами, может работать с циклом среди всех диапазонов, но это неверно, поскольку все диапазоны могут перекрываться друг с другом, но не перекрываться все вместе.

Я надеюсь, что кто-то может помочь мне найти хорошее решение.....


person Aladdin Mhemed    schedule 14.03.2014    source источник


Ответы (3)


Ни одно из вышеперечисленных решений на самом деле не сработало для меня, я использую здесь Carbon API для сравнения дат, но это может быть достигнуто путем обычного сравнения дат PHP, если вы не используете Carbon API.

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;
}
person Nishant Goel    schedule 23.08.2020
comment
Чтобы заменить функцию нативным PHP-кодом, вы можете использовать if ($start_first <= $end && $end_first >= $start) { // overlap } - person 4thfloorstudios; 04.09.2020

основанный на ответе Раифа Рефаи, алгоритм проверяет только даты рядом друг с другом, но не как весь список диапазонов дат. вот исправленная версия. надеюсь это поможет.

$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;
      }
    }
  }
}
person fazrinwiraman    schedule 26.11.2018

person    schedule
comment
Если в первой итерации цикла перекрытия нет, функция вернет false и дальнейших сравнений производиться не будет. - person cmcnulty; 28.08.2014
comment
эта функция предназначена для поиска общего пересечения, поэтому, если между первыми двумя нет пересечения, это ложно. - person Raeef Refai; 03.09.2014
comment
Спасибо за объяснение. Я понял, что ОП хочет знать, перекрываются ли какие-либо и перекрываются ли все, но, перечитывая его, трудно точно знать, какой сценарий искал ОП. - person cmcnulty; 04.09.2014