From 71171e179efe4b4a2fb717bbebde78b1149cfdf1 Mon Sep 17 00:00:00 2001 From: Victor Viruete Date: Tue, 16 Jul 2019 20:43:07 +0200 Subject: [PATCH] added TimeSlot.from function - wip --- lib/open_hours/time_slot.ex | 37 +++++++++++++++++++++++++++--- test/open_hours/time_slot_test.exs | 35 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/lib/open_hours/time_slot.ex b/lib/open_hours/time_slot.ex index a7ed41d..c7b7978 100644 --- a/lib/open_hours/time_slot.ex +++ b/lib/open_hours/time_slot.ex @@ -44,13 +44,44 @@ defmodule OpenHours.TimeSlot do |> DateTime.to_date() |> Date.range(DateTime.to_date(ends_at)) |> Enum.reject(&Enum.member?(schedule.holidays, &1)) - |> Enum.flat_map(&time_slots_for(schedule, starts_at, ends_at, &1)) + |> Enum.flat_map(&time_slots_for(schedule, &1)) + end + + @doc """ + """ + @spec from(OpenHours.Schedule.t(), DateTime.t(), integer) :: [t()] + def from( + %Schedule{time_zone: schedule_tz} = schedule, + %DateTime{time_zone: instant_tz} = instant, + limit \\ 1 + ) + when schedule_tz != instant_tz do + {:ok, shifted_instant} = DateTime.shift_zone(instant, schedule_tz, Tzdata.TimeZoneDatabase) + from(schedule, shifted_instant, limit) + end + + def from(%Schedule{} = schedule, %DateTime{} = instant, limit) do + date_to_check = DateTime.to_date(instant) + from_scan(schedule, instant, limit, [], date_to_check) + end + + defp from_scan(_schedule, _instant, limit, acc, _date_to_check) when length(acc) == limit, do: acc + + defp from_scan(schedule, instant, limit, acc, date_to_check) do + slots = time_slots_for(schedule, date_to_check) + max = limit - length(acc) + next_date_to_check = Date.add(date_to_check, 1) + + matching_slots = + slots + |> Enum.filter(fn %TimeSlot{ends_at: ends_at} -> ends_at >= instant end) + |> Enum.take(max) + + from_scan(schedule, instant, limit, acc ++ matching_slots, next_date_to_check) end defp time_slots_for( %Schedule{} = schedule, - %DateTime{} = _starts_at, - %DateTime{} = _ends_at, %Date{} = day ) do schedule diff --git a/test/open_hours/time_slot_test.exs b/test/open_hours/time_slot_test.exs index 4dec641..d8d4230 100644 --- a/test/open_hours/time_slot_test.exs +++ b/test/open_hours/time_slot_test.exs @@ -77,6 +77,41 @@ defmodule OpenHours.TimeSlotTest do end end + describe "from/3" do + test "returns proper timeslots when schedule contains data" do + schedule = %Schedule{ + hours: %{ + mon: [{~T[09:00:00], ~T[14:00:00]}, {~T[15:00:00], ~T[20:00:00]}], + tue: [{~T[09:00:00], ~T[14:00:00]}, {~T[15:00:00], ~T[20:00:00]}], + wed: [{~T[09:00:00], ~T[14:00:00]}, {~T[15:00:00], ~T[20:00:00]}], + thu: [{~T[09:00:00], ~T[14:00:00]}, {~T[15:00:00], ~T[20:00:00]}] + }, + breaks: [ + # Wednesday + {~D[2019-07-16], [{~T[15:00:00], ~T[20:00:00]}]}, + {~D[2019-07-17], [{~T[09:00:00], ~T[14:00:00]}]} + ], + time_zone: "Europe/Madrid" + } + + # Tuesday + instant = build_dt(~N[2019-07-16 12:00:00]) + + expected_time_slots = [ + %TimeSlot{ + starts_at: build_dt(~N[2019-07-16 09:00:00]), + ends_at: build_dt(~N[2019-07-16 14:00:00]) + }, + %TimeSlot{ + starts_at: build_dt(~N[2019-07-17 15:00:00]), + ends_at: build_dt(~N[2019-07-17 20:00:00]) + } + ] + + assert TimeSlot.from(schedule, instant, 2) == expected_time_slots + end + end + defp build_dt(naive_datetime) do DateTime.from_naive!(naive_datetime, "Europe/Madrid", Tzdata.TimeZoneDatabase) end