This script checks if a 60 min slot is available within a time range taking into account already booked slots. It works fine for the first already booked slot but does not take into account the second. Also if I change the first booked slot to 12:10 it will not detect it.
Basically, the idea is if there is a 60 min slot between the range and the already booked slots to show it.
For example,, if we have a range 9:00
to 15:00
and we have two booked slots from 11:10
and 14:00
, to return available slots from 9:00, 10:00 and 12:10
$start_time = '2022-10-21 09:00:00'; //start time as string
$end_time = '2022-10-21 15:00:00'; //end time as string
$booked = ['2022-10-21 12:00:00','2022-10-21 13:00:00']; //booked slots as arrays
$start = DateTime::createFromFormat('Y-m-d H:i:s',$start_time); //create date time objects
$end = DateTime::createFromFormat('Y-m-d H:i:s',$end_time); //create date time objects
$time1 = $start;
$count = 0; //number of slots
$out = array(); //array of slots
for($i = $start; $i<$end;) //for loop
{
$avoid = false;
$t1 = date_timestamp_get($i);
$t2 = $t1+(60*60);
for($k=0;$k<sizeof($booked);$k+=2) //if booked hour
{
$st = DateTime::createFromFormat('Y-m-d H:i:s',$booked[$k]);
$en = DateTime::createFromFormat('Y-m-d H:i:s',$booked[$k+1]);
if( $t1 >= date_timestamp_get($st) && $t2 <= date_timestamp_get($en) )
$avoid = true; //yes. booked
}
$slots =[ $i->format('H:i'),$i->modify("+60 minutes")->format('H:i')];
if(!$avoid && $i<$end) //if not booked and less than end time
{
$count++;
array_push($out,$slots); //add slot to array
}
}
var_dump($out); //array out
Here is link to sandbox https://onlinephp.io/c/b0b77
Additional information
Let's say that we have a free time frame from 10:00 until 13:00
. What the script should return is 10:00
, 11:00
, and 12:00
as possibilities if the time slot is 60 min
.
If the timeslot is 45 min
. for example, it should return 10:00
, 10:45
, 11:30
, and 12:15
.
So, the possible variants should start from the first possible option increasing with the time slot (45, 60, or whatever time slot is set
)
The slot cannot start from 10:12, 10:44, or another custom time
The Solutions
Both solutions below by Salman A
and Jim
are working as expected. Just use a little bit of a different approach.
Overlapping bookings - Update provided
If you have overlapping bookings as suggested by Salman A
we have to first merge them and then send unique intervals only.
I did it with that function
function mergeBookings($ranges)
{
$retVal = [];
//sort date ranges by begin time
usort($ranges, function ($a, $b) {
return strcmp($a['start'], $b['start']);
});
$currentRange = [];
foreach ($ranges as $range) {
// bypass invalid value
if ($range['start'] >= $range['end']) {
continue;
}
//fill in the first element
if (empty($currentRange)) {
$currentRange = $range;
continue;
}
if ($currentRange['end'] < $range['start']) {
$retVal[] = $currentRange;
$currentRange = $range;
} elseif ($currentRange['end'] < $range['end']) {
$currentRange ['end'] = $range['end'];
}
}
if ($currentRange) {
$retVal[] = $currentRange;
}
return $retVal;
}
Then just use the function before sending the $booked array to the script. Like this
$booked = mergeBookings($booked);