Burndog
Burndog

Reputation: 719

How to identify dates that intersect x times within ranges in php?

We are looking to create a list of comma separated dates that tell us when a reservation is full. There are 7 units to rent so we want to know which dates are present >= 7

This Stackoverflow thread is close as it identifies intersections but I am looking for the specific dates where they intersect x amount of times.

<?php 

// 2019-2-21 is present 8 times in the following array
$ranges = array(
        array('id' =>'59','start' => new DateTime('2019-02-19'), 'end' => new DateTime('2019-02-21')), 
        array('id' =>'58','start' => new DateTime('2019-02-19'), 'end' => new DateTime('2019-02-21')), 
        array('id' =>'55','start' => new DateTime('2019-02-19'), 'end' => new DateTime('2019-02-21')), 
        array('id' =>'57','start' => new DateTime('2019-02-19'), 'end' => new DateTime('2019-02-21')), 
        array('id' =>'108','start' => new DateTime('2019-02-21'), 'end' => new DateTime('2019-02-28')), 
        array('id' =>'109','start' => new DateTime('2019-02-19'), 'end' => new DateTime('2019-02-24')), 
        array('id' =>'110','start' => new DateTime('2019-02-21'), 'end' => new DateTime('2019-02-23')), 
        array('id' =>'111','start' => new DateTime('2019-02-21'), 'end' => new DateTime('2019-02-25')),  
        );

function intersects($lhs, $rhs) {
    return !($lhs['start'] > $rhs['end']  || $lhs['end'] < $rhs['start']);
}

function checkDates($ranges) {
    // Comparison loop 
    for($i = 0; $i < sizeof($ranges); $i++) {

        for($j = $i+1; $j < sizeof($ranges); $j++) {
            if(intersects($ranges[$i], $ranges[$j])) {
                echo "Date {$i} intersects with date {$j}<br>";
                }
            }
    }
}

    checkDates($ranges);
?>

I'm able to identify on a known specific date when we are over the limit

SELECT COUNT(*) FROM reservations 
WHERE reservations.`date` <= '$date' AND reservations.`dateLast` >= '$date'

This gives us a count that we can compare to our qty of units but I'm not sure how to create a list of dates that intersect >= x so we can know in advance if we are sold out.

UPDATE to confirm solution:

foreach ($ranges as $range) {
while ($range['start'] <= $range['end']) {
    $date = $range['start']->format('Y-m-d');
    $dates[$date] = (isset($dates[$date]) ? $dates[$date] : 0) + 1; 1;//define new $dates array
   $range['start']->modify('+1 day');
    }
}


 echo  $sold_out = array_filter($dates, function($n) { return $n >= 7; });



   echo '<pre>';
   print_r($range);
   echo '</pre>';

Upvotes: 2

Views: 94

Answers (1)

Don&#39;t Panic
Don&#39;t Panic

Reputation: 41810

I think you don't need to intersect the ranges. You just need to know how many times each date appears in your list of ranges, so you can just iterate each range in ranges and count the dates.

foreach ($ranges as $range) {
    while ($range['start'] <= $range['end']) {
        $date = $range['start']->format('Y-m-d');
        $dates[$date] = ($dates[$date] ?? 0) + 1;
        // or $dates[$date] = (isset($dates[$date]) ? $dates[$date] : 0) + 1;
        $range['start']->modify('+1 day');
    }
}

/* Result:

array (size=10)
'2019-02-19' => int 5
'2019-02-20' => int 5
'2019-02-21' => int 8
'2019-02-22' => int 4 ...
*/

Then you can filter that to find any sold out dates.

$sold_out = array_filter($dates, function($n) { return $n >= 7; });

I think you can probably also do this in SQL by creating a temporary table with all dates in the date range you're interested in and joining it to your count query.

Upvotes: 1

Related Questions