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
4
Answers
The algorithm you need to implement is as follows (I’m implementing it in pseudo-code for now):
The reason as of why I didn’t implement this in PHP was that I did not have enough time to do so at the time of this writing. Let me know if this is not clear yet and whether you need PHP code.
It is simple nested loops:
You can use
DatePeriod
combined withDateInterval
to create ranges or slots to which you can then check if the slot intersects with any of the booked slots:Here I have created a function which creates a
DatePeriod
for each of the booked slots by using the start date & time and adding the booking interval (minus 1 second) to set the end time. The 1 second is subtracted so that it doesn’t book the next time slot. For instance, if the slot is 1 hour long and 1:00 is booked that is 1:00 to 2:00. However, the next slot starts at 2:00 so 2:00 would not show as available. 1 second is removed making it 59 minutes and 59 seconds so the end is 1:59:59. The 2:00 slot is now available. Keep that in mind if you use it to display a booked slot’s length.Note that you may need to add a second or people may be confused why it shows 59 minutes and 59 seconds.
The second function,
isAvailable
, is called within the loop to check if the time slot is booked or not. It compares the slot’s start time is between any of the start and end times of the booked slots. If so, it is already booked. If not, it is added to the$availableToBook
array.You can change the booking length by altering
$bookingLength
to whatever you want (it is set to one hour). You can change it to 15 minutes (PT15M
), 30 minutes (PT30M
), 45 minutes (PT45M
), or whatever time length you want.My approach was to essentially use the booked slots to split the given timeframe into available time periods. Available time slots are then allocated to the larger time periods separately. I believe this results in less loop iterations and should be better for performance (not that it matters much for small time frames).
I split the functionality for determining the available time periods and allocating the available time slots into separate functions for better readability.
This solution should be adaptive enough for the
$slotLength
DateInterval
to be updated to accommodate all different slot lengths up to 24 hours. I know in your question that you addressed dates as string values, however I believe it’s much more side effect free and type safe to utilise PHP’s built in date related objects e.g.DateTimeImmutable
,DateInterval
where possible, therefore my solution follows this approach.