I am looking for help designing the display of available times for appointments (for example a hairdresser’s appointment book).
Currently I have a query that returns a collection of periods that are unavailable for appointments (whether there is an existing appointment or if the service provider is closed).
So lets say Feb 3rd, from 12 to 5 is unavailable, i want to output the following string:
Jan 1st 12 am – Feb 3rd 12pm
Feb 3rd, 5pm – Dec 31 12 am.
My entire range is 1 year from Jan 1st to December 31st and there can be as many unavailable dates.
11
If overlap is not allowed, a rather simple process can be followed:
-
Add an appointment starting at
31 Dec 12 AM
(ending any time). -
Sort the appointments.
-
Initialize
lastTime
to1 Jan 12 AM
. -
For each appointment:
OutputlastTime
to the start of this appointment.
SetlastTime
= the end of this appointment.
If overlap is allowed, this requires a sweep-line algorithm:
-
Split the appointments into start and end times and sort them.
If a start time and an end time are equal, put the start time first (otherwise you may get 0 duration outputs). -
Add
31 Dec 12 AM
as a start time. -
Initialize
lastTime
to1 Jan 12 AM
. -
Initialize a
count
variable to 0. This variable will, at any time, indicate how many appointments are busy at the current point in time. -
Iterate through the times.
If we encounter a start time:
-
If
count
= 0, outputlastTime
to this time. -
Increment
count
.
If we encounter an end time:
-
Decrement
count
. -
Set
lastTime
to this time.
-
If the appointments can go beyond the given range, that should be simple enough to deal with:
For the first algorithm, start at the first appointment that ends after 1 Jan 12 AM
and end before any appointment after 31 Dec 12 AM
.
For the second, just initialize count
to the number of appointments that runs through 1 Jan 12 AM
and ignore points outside the given range.
Given your starting point the solution is pretty straight forward. Assume that you start with all times being available so your initial display will be:
Jan 1st 12:00am – Dec 31st 11:59pm
Assuming that the appointment times are in chronological order and there is no overlap with any of them (if not, you should be able to make an algorithm to fix up the list for you) the solution is simple.
For each “unavailable” slot:
- Take the last available slot and split it into two
- set the start time of the first slot to the start time of the original
- set the end time of the first slot to the start time of the “unavailable” slot
- set the start time of the second slot to the end time of the “unavailable” slot
- set the end time of the second slot to the end time of the original.
Once you’ve down that you’ll have a list of available slots. Here’s an example:
Original availability is Jan 1st 12:00 AM – Dec 31st 11:59 PM
you have the following “unavailable” slots
Jan 15th 12:00 AM – Jan 15th 11:59 PM
Jan 20th 12:00 PM – Feb 4th 9:00 AM
Feb 14th 1:00 PM – Feb 14th 5:00 PM
The first run of the algorithm would look like so
Original Jan 1st 12:00 AM – Dec 31st 11:59 PM
Split into two
First runs Start of original to start of “unavailable”
Jan 1st 12:00 AM – Jan 15th 12:00 AM
Second runs End of “unavailable” to end of original
Jan 15th 11:59 PM – Dec 31st 11:59 PM
So now you have two available slots
Jan 1st 12:00 AM – Jan 15th 12:00 AM
Jan 15th 11:59 PM – Dec 31st 11:59 PM
Do the same operations with the next two and you’re home free.
Don’t forget edge cases.
What happens when you have an available slot that is essential zero in length?
What happens when one of the “unavailable slots runs past the end or before the beginning of your window?