diff --git a/.tool-versions b/.tool-versions index 0b827a9..532f92b 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -elixir 1.12.1-otp-24 -erlang 24.0.2 +elixir 1.14.5-otp-25 +erlang 25.3.2 diff --git a/lib/cocktail/builder/i_calendar.ex b/lib/cocktail/builder/i_calendar.ex index 35cf3be..41189bf 100644 --- a/lib/cocktail/builder/i_calendar.ex +++ b/lib/cocktail/builder/i_calendar.ex @@ -5,6 +5,8 @@ defmodule Cocktail.Builder.ICalendar do TODO: write long description """ + import Cocktail.Util + alias Cocktail.{Rule, Schedule, Validation} alias Cocktail.Validation.{Day, DayOfMonth, HourOfDay, Interval, MinuteOfHour, SecondOfMinute, TimeOfDay, TimeRange} @@ -106,7 +108,7 @@ defmodule Cocktail.Builder.ICalendar do defp build_end_time(%Schedule{start_time: start_time, duration: duration}) do start_time - |> Timex.shift(seconds: duration) + |> shift_time(seconds: duration) |> build_time("DTEND") end diff --git a/lib/cocktail/schedule_state.ex b/lib/cocktail/schedule_state.ex index 0d257ff..492371a 100644 --- a/lib/cocktail/schedule_state.ex +++ b/lib/cocktail/schedule_state.ex @@ -2,6 +2,7 @@ defmodule Cocktail.ScheduleState do @moduledoc false alias Cocktail.{RuleState, Schedule, Span} + import Cocktail.Util @type t :: %__MODULE__{ recurrence_rules: [RuleState.t()], @@ -114,7 +115,7 @@ defmodule Cocktail.ScheduleState do | recurrence_rules: rules, recurrence_times: times, exception_times: exceptions, - current_time: Timex.shift(time, seconds: 1) + current_time: shift_time(time, seconds: 1) } {occurrence, new_state} @@ -122,7 +123,7 @@ defmodule Cocktail.ScheduleState do @spec span_or_time(Cocktail.time() | nil, pos_integer | nil) :: Cocktail.occurrence() defp span_or_time(time, nil), do: time - defp span_or_time(time, duration), do: Span.new(time, Timex.shift(time, seconds: duration)) + defp span_or_time(time, duration), do: Span.new(time, shift_time(time, seconds: duration)) @spec min_time_for_rules([RuleState.t()]) :: Cocktail.time() | nil defp min_time_for_rules([]), do: nil diff --git a/lib/cocktail/util.ex b/lib/cocktail/util.ex index 637e86b..21a85f5 100644 --- a/lib/cocktail/util.ex +++ b/lib/cocktail/util.ex @@ -3,4 +3,26 @@ defmodule Cocktail.Util do def next_gte([], _), do: nil def next_gte([x | rest], search), do: if(x >= search, do: x, else: next_gte(rest, search)) + + def beginning_of_day(time) do + time + |> Timex.beginning_of_day() + |> no_ms() + end + + def beginning_of_month(time) do + time + |> Timex.beginning_of_month() + |> no_ms() + end + + def shift_time(datetime, opts) do + datetime + |> Timex.shift(opts) + |> no_ms() + end + + def no_ms(time) do + Map.put(time, :microsecond, {0, 0}) + end end diff --git a/lib/cocktail/validation/day_of_month.ex b/lib/cocktail/validation/day_of_month.ex index acbaf8f..8c2d78a 100644 --- a/lib/cocktail/validation/day_of_month.ex +++ b/lib/cocktail/validation/day_of_month.ex @@ -2,7 +2,7 @@ defmodule Cocktail.Validation.DayOfMonth do @moduledoc false import Cocktail.Validation.Shift - import Cocktail.Util, only: [next_gte: 2] + import Cocktail.Util # assumed that DST can not "take" more than 4 hours between any 2 consecutive days @min_dst_resultant_hours 20 @@ -28,9 +28,7 @@ defmodule Cocktail.Validation.DayOfMonth do case next_gte(normalized_days, current_day_of_month) do # go to next month nil -> - next_month_time = - time - |> Timex.shift(months: 1) + next_month_time = shift_time(time, months: 1) next_month_normalized_days = Enum.map(days, &normalize_day_of_month(&1, next_month_time)) next_month_earliest_day = Timex.set(next_month_time, day: hd(Enum.sort(next_month_normalized_days))) diff --git a/lib/cocktail/validation/interval.ex b/lib/cocktail/validation/interval.ex index 17a8c91..4f5ca43 100644 --- a/lib/cocktail/validation/interval.ex +++ b/lib/cocktail/validation/interval.ex @@ -3,6 +3,7 @@ defmodule Cocktail.Validation.Interval do import Integer, only: [mod: 2, floor_div: 2] import Cocktail.Validation.Shift + import Cocktail.Util @typep iso_week :: {Timex.Types.year(), Timex.Types.weeknum()} @@ -20,8 +21,8 @@ defmodule Cocktail.Validation.Interval do def next_time(%__MODULE__{type: :monthly, interval: interval}, time, start_time) do start_time - |> Timex.beginning_of_month() - |> Timex.diff(Timex.beginning_of_month(time), :months) + |> beginning_of_month() + |> Timex.diff(beginning_of_month(time), :months) |> mod(interval) |> shift_by(:months, time) end diff --git a/lib/cocktail/validation/schedule_lock.ex b/lib/cocktail/validation/schedule_lock.ex index 72fd331..5769e63 100644 --- a/lib/cocktail/validation/schedule_lock.ex +++ b/lib/cocktail/validation/schedule_lock.ex @@ -3,6 +3,7 @@ defmodule Cocktail.Validation.ScheduleLock do import Integer, only: [mod: 2] import Cocktail.Validation.Shift + import Cocktail.Util @type lock :: :second | :minute | :hour | :wday | :mday @@ -34,7 +35,7 @@ defmodule Cocktail.Validation.ScheduleLock do def next_time(%__MODULE__{type: :mday}, time, start_time) do if start_time.day > Calendar.ISO.days_in_month(time.year, time.month) do - next_time(%__MODULE__{type: :mday}, Timex.shift(time, months: 1), start_time) + next_time(%__MODULE__{type: :mday}, shift_time(time, months: 1), start_time) else next_mday_time(%__MODULE__{type: :mday}, time, start_time) end @@ -56,7 +57,7 @@ defmodule Cocktail.Validation.ScheduleLock do |> Timex.diff(time, :days) start_time_day_of_month -> - next_month_date = Timex.shift(time, months: 1) + next_month_date = shift_time(time, months: 1) # Timex.set already handle the marginal case like setting a day of month more than the month contains next_month_date |> Timex.set(day: start_time_day_of_month) diff --git a/lib/cocktail/validation/shift.ex b/lib/cocktail/validation/shift.ex index 3e163f8..1c5c766 100644 --- a/lib/cocktail/validation/shift.ex +++ b/lib/cocktail/validation/shift.ex @@ -9,7 +9,7 @@ defmodule Cocktail.Validation.Shift do @typep option :: nil | :beginning_of_day | :beginning_of_hour | :beginning_of_minute - import Timex, only: [shift: 2, beginning_of_day: 1] + import Cocktail.Util @spec shift_by(integer, shift_type, Cocktail.time(), option) :: result def shift_by(amount, type, time, option \\ nil) @@ -18,7 +18,7 @@ defmodule Cocktail.Validation.Shift do def shift_by(amount, type, time, option) do new_time = time - |> shift("#{type}": amount) + |> shift_time("#{type}": amount) |> apply_option(option) {:change, new_time}