我有一个日期列表,表示一个房间的预订。我希望能够找到第一天在日期范围内的位置。
# 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>
]
我们希望在这里返回#DateTime<2019-02-04 00:00:00Z>
,因为这是第一个可用日期。
我已经考虑过将Enum.reduce_while
与Timex.Interval
结合使用,但是运气不好,因为reduce_while
似乎在第一次调用后返回了间隔。
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)
答案 0 :(得分:2)
尽管@Badu的答案是正确的,但我会以所需的Enum.reduce_while/3
发布解决方案。
Elixir如今首先具有对日期的强大内置支持,所以我怀疑我为什么要使用Timex
。而且,对于预订天数,您最好处理日期而不要处理日期时间(除非您允许按小时付费预订)。 ),但是,如果您要DateTime
,请前往:
# Please next time make your input available to copy-paste
[today | booked_days] =
[1, 8, 5, 3, 2]
|> Enum.map(& {{2019, 02, &1}, {0, 0, 0}}
|> NaiveDateTime.from_erl!()
|> DateTime.from_naive!("Etc/UTC"))
booked_days
|> Enum.sort(& Date.compare(&1, &2) == :lt)
|> Enum.reduce_while(today, fn d, curr ->
if Date.diff(d, curr) == 1,
do: {:cont, d},
else: {:halt, DateTime.add(curr, 3600 * 24)}
end)
#⇒ #DateTime<2019-02-04 00:00:00Z>
答案 1 :(得分:1)
首先,您可以按升序对日期进行排序。 然后对日期进行迭代,并检查日期之间的空间隔,如果日期大于或等于起始日期,则返回日期。
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
答案 2 :(得分:0)
此处没有Timex版本
使用[[1st date, 2nd date], [2nd date, 3rd date], .. [ith, (i-1)st]...]
(使用按偏移量1的zip格式)创建元素数组,然后找出两者相差超过1天的位置。
defmodule DateGetter do
def get_next_date(booked_dates) do
sorted = Enum.sort(booked_dates)
date = sorted
|> Enum.zip(Enum.drop sorted, 1) # or use Enum.chunk_every for large sizes
|> Enum.find(fn {d1, d2} -> DateTime.diff(d2, d1) > 86400 end)
case date do
nil ->
{:error, "no dates found"}
{date1, date2} ->
(DateTime.to_unix(date1) + 86400) |> DateTime.from_unix
end
end
end
# Sample input:
booked_dates =
[2,5,3,8]
|> Enum.map(fn d ->
DateTime.from_iso8601("2015-01-0#{d} 01:00:00Z")
|> elem(1)
end)
DateGetter.get_next_date booked_dates
#> {:ok, #DateTime<2015-01-04 01:00:00Z>}