Skip to content

Commit a8bc24e

Browse files
committed
Removes dependency on Timex
1 parent 230963f commit a8bc24e

27 files changed

Lines changed: 547 additions & 234 deletions

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
elixir 1.14.5-otp-25
2-
erlang 25.3.2
1+
elixir 1.15.6-otp-26
2+
erlang 26.1

lib/cocktail/builder/i_calendar.ex

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,18 @@ defmodule Cocktail.Builder.ICalendar do
55
TODO: write long description
66
"""
77

8-
import Cocktail.Util
9-
108
alias Cocktail.{Rule, Schedule, Validation}
119
alias Cocktail.Validation.{Day, DayOfMonth, HourOfDay, Interval, MinuteOfHour, SecondOfMinute, TimeOfDay, TimeRange}
1210

13-
@time_format_string "{YYYY}{0M}{0D}T{h24}{m}{s}"
11+
@time_format_string "%Y%m%dT%H%M%S"
1412

1513
@doc ~S"""
1614
Builds an iCalendar format string representation of a `t:Cocktail.Schedule.t/0`.
1715
1816
## Examples
1917
2018
iex> alias Cocktail.Schedule
21-
...> start_time = Timex.to_datetime(~N[2017-01-01 06:00:00], "America/Los_Angeles")
19+
...> start_time = Cocktail.Time.to_datetime(~N[2017-01-01 06:00:00], "America/Los_Angeles")
2220
...> schedule = Schedule.new(start_time)
2321
...> schedule = Schedule.add_recurrence_rule(schedule, :daily, interval: 2, hours: [10, 12])
2422
...> build(schedule)
@@ -64,7 +62,7 @@ defmodule Cocktail.Builder.ICalendar do
6462
## Examples
6563
6664
iex> alias Cocktail.Schedule
67-
...> start_time = Timex.to_datetime(~N[2017-01-01 06:00:00], "America/Los_Angeles")
65+
...> start_time = Cocktail.Time.to_datetime(~N[2017-01-01 06:00:00], "America/Los_Angeles")
6866
...> schedule = Schedule.new(start_time)
6967
...> schedule = Schedule.add_recurrence_rule(schedule, :daily, interval: 2, hours: [10, 12])
7068
...> build_rule(schedule)
@@ -91,12 +89,12 @@ defmodule Cocktail.Builder.ICalendar do
9189
@spec build_time(Cocktail.time(), String.t()) :: String.t()
9290
defp build_time(%DateTime{} = time, prefix) do
9391
timezone = time.time_zone
94-
time_string = Timex.format!(time, @time_format_string)
92+
time_string = Calendar.strftime(time, @time_format_string)
9593
"#{prefix};TZID=#{timezone}:#{time_string}"
9694
end
9795

9896
defp build_time(%NaiveDateTime{} = time, prefix) do
99-
time_string = Timex.format!(time, @time_format_string)
97+
time_string = Calendar.strftime(time, @time_format_string)
10098
"#{prefix}:#{time_string}"
10199
end
102100

@@ -108,17 +106,17 @@ defmodule Cocktail.Builder.ICalendar do
108106

109107
defp build_end_time(%Schedule{start_time: start_time, duration: duration}) do
110108
start_time
111-
|> shift_time(seconds: duration)
109+
|> Cocktail.Time.shift(duration, :second)
112110
|> build_time("DTEND")
113111
end
114112

115113
@spec build_utc_time(Cocktail.time()) :: String.t()
116-
defp build_utc_time(%NaiveDateTime{} = time), do: Timex.format!(time, @time_format_string)
114+
defp build_utc_time(%NaiveDateTime{} = time), do: Calendar.strftime(time, @time_format_string)
117115

118116
defp build_utc_time(%DateTime{} = time) do
119117
time
120-
|> Timex.to_datetime("UTC")
121-
|> Timex.format!(@time_format_string <> "Z")
118+
|> Cocktail.Time.to_datetime("UTC")
119+
|> Calendar.strftime(@time_format_string <> "Z")
122120
end
123121

124122
@spec do_build_rule(Rule.t()) :: String.t()

lib/cocktail/parser/i_calendar.ex

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ defmodule Cocktail.Parser.ICalendar do
88
alias Cocktail.{Rule, Schedule}
99

1010
@time_regex ~r/^:?;?(?:TZID=(.+?):)?(.*?)(Z)?$/
11-
@datetime_format "{YYYY}{0M}{0D}T{h24}{m}{s}"
12-
@time_format "{h24}{m}{s}"
11+
@datetime_format "%Y%m%dT%H%M%S"
12+
@time_format "%H%M%S"
1313

1414
@doc ~S"""
1515
Parses a string in iCalendar format into a `t:Cocktail.Schedule.t/0`.
@@ -38,7 +38,7 @@ defmodule Cocktail.Parser.ICalendar do
3838
|> String.trim()
3939
|> String.split("\n")
4040
|> Enum.map(&String.trim/1)
41-
|> parse_lines(Schedule.new(Timex.now()), 0)
41+
|> parse_lines(Schedule.new(DateTime.utc_now()), 0)
4242
end
4343

4444
@spec parse_lines([String.t()], Schedule.t(), non_neg_integer) :: {:ok, Schedule.t()} | {:error, term}
@@ -105,15 +105,17 @@ defmodule Cocktail.Parser.ICalendar do
105105
end
106106

107107
@spec parse_naive_datetime(String.t()) :: {:ok, NaiveDateTime.t()} | {:error, term}
108-
defp parse_naive_datetime(time_string), do: Timex.parse(time_string, @datetime_format)
108+
defp parse_naive_datetime(time_string) do
109+
Cocktail.Time.parse(time_string, @datetime_format)
110+
end
109111

110112
@spec parse_utc_datetime(String.t()) :: {:ok, DateTime.t()} | {:error, term}
111-
defp parse_utc_datetime(time_string), do: parse_zoned_datetime(time_string, "UTC")
113+
defp parse_utc_datetime(time_string), do: parse_zoned_datetime(time_string, "Etc/UTC")
112114

113115
@spec parse_zoned_datetime(String.t(), String.t()) :: {:ok, DateTime.t()} | {:error, term}
114116
defp parse_zoned_datetime(time_string, zone) do
115-
with {:ok, naive_datetime} <- Timex.parse(time_string, @datetime_format),
116-
%DateTime{} = datetime <- Timex.to_datetime(naive_datetime, zone) do
117+
with {:ok, naive_datetime} <- Cocktail.Time.parse(time_string, @datetime_format),
118+
%DateTime{} = datetime <- Cocktail.Time.to_datetime(naive_datetime, zone) do
117119
{:ok, datetime}
118120
end
119121
end
@@ -421,7 +423,8 @@ defmodule Cocktail.Parser.ICalendar do
421423

422424
@spec parse_time(String.t()) :: {:ok, Time.t()} | {:error, :invalid_time_format}
423425
defp parse_time(time_string) do
424-
case Timex.parse(time_string, @time_format) do
426+
case Cocktail.Time.parse(time_string, @time_format) do
427+
{:ok, %Time{} = time} -> {:ok, time}
425428
{:ok, datetime} -> {:ok, NaiveDateTime.to_time(datetime)}
426429
_error -> {:error, :invalid_time_format}
427430
end

lib/cocktail/rule_state.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ defmodule Cocktail.RuleState do
7777
defp new_state(%__MODULE__{until: nil} = rule_state, time), do: %{rule_state | current_time: time}
7878

7979
defp new_state(%__MODULE__{until: until} = rule_state, time) do
80-
if Timex.compare(until, time) == -1 do
80+
if Cocktail.Time.compare(until, time) == :lt do
8181
%{rule_state | current_time: nil}
8282
else
8383
%{rule_state | current_time: time}

lib/cocktail/schedule.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ defmodule Cocktail.Schedule do
8484
@doc false
8585
@spec set_end_time(t, Cocktail.time()) :: t
8686
def set_end_time(%__MODULE__{start_time: start_time} = schedule, end_time) do
87-
duration = Timex.diff(end_time, start_time, :seconds)
87+
duration = Cocktail.Time.diff(end_time, start_time, :second)
8888
%{schedule | duration: duration}
8989
end
9090

@@ -180,9 +180,9 @@ defmodule Cocktail.Schedule do
180180
~N[2017-10-04 10:00:00]]
181181
182182
# using a DateTime with a time zone
183-
iex> start_time = Timex.to_datetime(~N[2017-01-02 10:00:00], "America/Los_Angeles")
183+
iex> start_time = Cocktail.Time.to_datetime(~N[2017-01-02 10:00:00], "America/Los_Angeles")
184184
...> schedule = start_time |> new() |> add_recurrence_rule(:daily)
185-
...> schedule |> occurrences() |> Enum.take(3) |> Enum.map(&Timex.format!(&1, "{ISO:Extended}"))
185+
...> schedule |> occurrences() |> Enum.take(3) |> Enum.map(&DateTime.to_iso8601/1)
186186
["2017-01-02T10:00:00-08:00",
187187
"2017-01-03T10:00:00-08:00",
188188
"2017-01-04T10:00:00-08:00"]

lib/cocktail/schedule_state.ex

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ defmodule Cocktail.ScheduleState do
22
@moduledoc false
33

44
alias Cocktail.{RuleState, Schedule, Span}
5-
import Cocktail.Util
65

76
@type t :: %__MODULE__{
87
recurrence_rules: [RuleState.t()],
@@ -26,19 +25,19 @@ defmodule Cocktail.ScheduleState do
2625

2726
def new(%Schedule{} = schedule, current_time) do
2827
current_time =
29-
if Timex.compare(current_time, schedule.start_time) < 0,
28+
if Cocktail.Time.compare(current_time, schedule.start_time) == :lt,
3029
do: schedule.start_time,
3130
else: current_time
3231

3332
recurrence_times_after_current_time =
3433
schedule.recurrence_times
35-
|> Enum.filter(&(Timex.compare(&1, current_time) >= 0))
36-
|> Enum.sort(&(Timex.compare(&1, &2) <= 0))
34+
|> Enum.filter(&(Cocktail.Time.compare(&1, current_time) in [:gt, :eq]))
35+
|> Enum.sort(&(Cocktail.Time.compare(&1, &2) in [:lt, :eq]))
3736

3837
%__MODULE__{
3938
recurrence_rules: schedule.recurrence_rules |> Enum.map(&RuleState.new/1),
4039
recurrence_times: recurrence_times_after_current_time,
41-
exception_times: schedule.exception_times |> Enum.sort(&(Timex.compare(&1, &2) <= 0)),
40+
exception_times: schedule.exception_times |> Enum.sort(&(Cocktail.Time.compare(&1, &2) in [:lt, :eq])),
4241
start_time: schedule.start_time,
4342
current_time: current_time,
4443
duration: schedule.duration
@@ -84,7 +83,7 @@ defmodule Cocktail.ScheduleState do
8483
defp next_time_from_recurrence_times([next_time | rest], nil), do: {next_time, rest}
8584

8685
defp next_time_from_recurrence_times([next_time | rest] = times, current_time) do
87-
if Timex.compare(next_time, current_time) <= 0 do
86+
if Cocktail.Time.compare(next_time, current_time) in [:lt, :eq] do
8887
{next_time, rest}
8988
else
9089
{current_time, times}
@@ -96,7 +95,7 @@ defmodule Cocktail.ScheduleState do
9695
defp apply_exception_time(exceptions, nil), do: {false, exceptions}
9796

9897
defp apply_exception_time([next_exception | rest] = exceptions, current_time) do
99-
if Timex.compare(next_exception, current_time) == 0 do
98+
if Cocktail.Time.compare(next_exception, current_time) == :eq do
10099
{true, rest}
101100
else
102101
{false, exceptions}
@@ -115,23 +114,23 @@ defmodule Cocktail.ScheduleState do
115114
| recurrence_rules: rules,
116115
recurrence_times: times,
117116
exception_times: exceptions,
118-
current_time: shift_time(time, seconds: 1)
117+
current_time: Cocktail.Time.shift(time, 1, :second)
119118
}
120119

121120
{occurrence, new_state}
122121
end
123122

124123
@spec span_or_time(Cocktail.time() | nil, pos_integer | nil) :: Cocktail.occurrence()
125124
defp span_or_time(time, nil), do: time
126-
defp span_or_time(time, duration), do: Span.new(time, shift_time(time, seconds: duration))
125+
defp span_or_time(time, duration), do: Span.new(time, Cocktail.Time.shift(time, duration, :second))
127126

128127
@spec min_time_for_rules([RuleState.t()]) :: Cocktail.time() | nil
129128
defp min_time_for_rules([]), do: nil
130129
defp min_time_for_rules([rule]), do: rule.current_time
131130

132131
defp min_time_for_rules(rules) do
133132
rules
134-
|> Enum.min_by(&Timex.to_erl(&1.current_time))
133+
|> Enum.min_by(&Cocktail.Time.to_erl(&1.current_time))
135134
|> Map.get(:current_time)
136135
end
137136

lib/cocktail/span.ex

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ defmodule Cocktail.Span do
3939
def new(from, until), do: %__MODULE__{from: from, until: until}
4040

4141
@doc """
42-
Uses `Timex.compare/2` to determine which span comes first.
42+
Uses `Cocktail.Time.compare/2` to determine which span comes first.
4343
4444
Compares `from` first, then, if equal, compares `until`.
4545
@@ -48,21 +48,21 @@ defmodule Cocktail.Span do
4848
iex> span1 = new(~N[2017-01-01 06:00:00], ~N[2017-01-01 10:00:00])
4949
...> span2 = new(~N[2017-01-01 06:00:00], ~N[2017-01-01 10:00:00])
5050
...> compare(span1, span2)
51-
0
51+
:eq
5252
5353
iex> span1 = new(~N[2017-01-01 06:00:00], ~N[2017-01-01 10:00:00])
5454
...> span2 = new(~N[2017-01-01 07:00:00], ~N[2017-01-01 12:00:00])
5555
...> compare(span1, span2)
56-
-1
56+
:lt
5757
5858
iex> span1 = new(~N[2017-01-01 06:00:00], ~N[2017-01-01 10:00:00])
5959
...> span2 = new(~N[2017-01-01 06:00:00], ~N[2017-01-01 07:00:00])
6060
...> compare(span1, span2)
61-
1
61+
:gt
6262
"""
63-
@spec compare(span_compat, span_compat) :: Timex.Comparable.compare_result()
64-
def compare(%{from: t, until: until1}, %{from: t, until: until2}), do: Timex.compare(until1, until2)
65-
def compare(%{from: from1}, %{from: from2}), do: Timex.compare(from1, from2)
63+
@spec compare(span_compat, span_compat) :: :lt | :eq | :gt
64+
def compare(%{from: t, until: until1}, %{from: t, until: until2}), do: Cocktail.Time.compare(until1, until2)
65+
def compare(%{from: from1}, %{from: from2}), do: Cocktail.Time.compare(from1, from2)
6666

6767
@doc """
6868
Returns an `t:overlap_mode/0` to describe how the first span overlaps the second.
@@ -94,16 +94,16 @@ defmodule Cocktail.Span do
9494

9595
# credo:disable-for-next-line
9696
def overlap_mode(%{from: from1, until: until1}, %{from: from2, until: until2}) do
97-
from_comp = Timex.compare(from1, from2)
98-
until_comp = Timex.compare(until1, until2)
97+
from_comp = Cocktail.Time.compare(from1, from2)
98+
until_comp = Cocktail.Time.compare(until1, until2)
9999

100100
cond do
101-
from_comp <= 0 && until_comp >= 0 -> :contains
102-
from_comp >= 0 && until_comp <= 0 -> :is_inside
103-
Timex.compare(until1, from2) <= 0 -> :is_before
104-
Timex.compare(from1, until2) >= 0 -> :is_after
105-
from_comp < 0 && until_comp < 0 -> :overlaps_the_start_of
106-
from_comp > 0 && until_comp > 0 -> :overlaps_the_end_of
101+
from_comp in [:lt, :eq] && until_comp in [:gt, :eq] -> :contains
102+
from_comp in [:gt, :eq] && until_comp in [:lt, :eq] -> :is_inside
103+
Cocktail.Time.compare(until1, from2) in [:lt, :eq] -> :is_before
104+
Cocktail.Time.compare(from1, until2) in [:gt, :eq] -> :is_after
105+
from_comp == :lt && until_comp == :lt -> :overlaps_the_start_of
106+
from_comp == :gt && until_comp == :gt -> :overlaps_the_end_of
107107
end
108108
end
109109
end

0 commit comments

Comments
 (0)