I have a list of dates that represent bookings for a room. I want to be able to find out where the first available day is in the date range.
# let us assume today is the 1st Feb
today = #DateTime<2019-02-01 00:00:00Z>
# here are our booked days
booked_days = [
#DateTime<2019-02-08 00:00:00Z>,
#DateTime<2019-02-05 00:00:00Z>,
#DateTime<2019-02-03 00:00:00Z>,
#DateTime<2019-02-02 00:00:00Z>
]
What we’d like to have returned here is #DateTime<2019-02-04 00:00:00Z>
because it’s the first available date.
I’ve looked at doing something like this using Enum.reduce_while
in combination with Timex.Interval
, but with no luck as reduce_while
seems to return the interval after the first call.
today = Timex.now() |> Timex.beginning_of_day()
first_available =
Enum.reduce_while(booked_days, today, fn from, until ->
interval = Timex.Interval.new(from: from, until: until)
duration = Timex.Interval.duration(interval, :days)
if duration <= 1,
do: {:cont, from},
else: {:halt, interval}
end)
First, you can sort the dates in ascending order. Then iterate the dates and check for empty intervals between dates and return the date if the date is greater than or equal to from date.
sorted_dates = Enum.sort(booked_days , fn a, b -> Timex.compare(a, b, :days)<0 end)
get_next_booking_date(sorted_dates, today)
def get_next_booking_date([], _from_date) do
nil
end
def get_next_booking_date([_last_booking_date], _from_date) do
# You can add a day to last booking date and return that date or return nil depending on your need
# Timex.add(_last_booking_date, Timex.Duration.from_days(1))
nil
end
def get_next_booking_date([next, next2 | rest], from_date) do
# add a day to the current day and check if there's an empty interval and that the empty slot is greater than from date
temp_next = Timex.add(next, Timex.Duration.from_days(1))
if Timex.compare(temp_next, next2, :days) == -1 and Timex.compare(temp_next, from_date) >= 0 do
temp_next
else
get_next_booking_date([next2 | rest], from)
end
end