Reputation: 3971
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.
I hope someone can help me to find a good solution.....
Upvotes: 7
Views: 6461
Reputation: 1418
I convert the Carbon answer of Reef in pure 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>";
Upvotes: 0
Reputation: 41
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.
PS: Happy if someone can optimize this code.
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;
}
Upvotes: 3
Reputation: 79
based on Raeef Refai answer the algorithm only checks dates next to each other but not as a whole list of dateranges. 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;
}
}
}
}
Upvotes: 0
Reputation: 1521
<?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));
Upvotes: 1