0

我有一个代表房间预订的日期列表。我希望能够找出日期范围内第一个可用日期的位置。

# 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)
4

3 回答 3

2

尽管@Badu 的答案是正确的,但我会使用所需的Enum.reduce_while/3.

Elixir 现在首先对日期有很好的内置支持,所以我怀疑我是否理解你为什么需要Timex. 当涉及到预订天数时,您最好处理日期而不是日期时间(除非您允许按小时付费预订。)但是,如果您想要s,那么您可以: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>
于 2019-02-28T06:10:45.117 回答
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
于 2019-02-27T20:00:54.170 回答
0

这是没有 Timex 的版本

创建一个元素数组[[1st date, 2nd date], [2nd date, 3rd date], .. [ith, (i-1)st]...](使用 zip by offset 1),然后找到两者相差超过 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>}
于 2019-02-28T12:28:47.767 回答