Skip to content

Commit 563fd96

Browse files
support Duration in Date.range/3
1 parent ef1450d commit 563fd96

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

lib/elixir/lib/calendar/date.ex

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ defmodule Date do
8484
iex> Date.range(~D[1999-01-01], ~D[2000-01-01])
8585
Date.range(~D[1999-01-01], ~D[2000-01-01])
8686
87+
Alternatively, a range may be built from a first `Date` and a `Duration`:
88+
89+
iex> Date.range(~D[1999-01-01], Duration.new!(year: 1))
90+
Date.range(~D[1999-01-01], ~D[2000-01-01])
91+
8792
A range of dates implements the `Enumerable` protocol, which means
8893
functions in the `Enum` module can be used to work with
8994
ranges:
@@ -100,7 +105,7 @@ defmodule Date do
100105
101106
"""
102107
@doc since: "1.5.0"
103-
@spec range(Calendar.date(), Calendar.date()) :: Date.Range.t()
108+
@spec range(Calendar.date(), Calendar.date() | Duration.t()) :: Date.Range.t()
104109
def range(%{calendar: calendar} = first, %{calendar: calendar} = last) do
105110
{first_days, _} = to_iso_days(first)
106111
{last_days, _} = to_iso_days(last)
@@ -119,6 +124,11 @@ defmodule Date do
119124
range(first, first_days, last, last_days, calendar, step)
120125
end
121126

127+
def range(%{calendar: calendar} = first, %Duration{} = duration) do
128+
last = shift(first, duration)
129+
range(first, last)
130+
end
131+
122132
def range(%{calendar: _, year: _, month: _, day: _}, %{calendar: _, year: _, month: _, day: _}) do
123133
raise ArgumentError, "both dates must have matching calendars"
124134
end
@@ -140,7 +150,7 @@ defmodule Date do
140150
141151
"""
142152
@doc since: "1.12.0"
143-
@spec range(Calendar.date(), Calendar.date(), step :: pos_integer | neg_integer) ::
153+
@spec range(Calendar.date(), Calendar.date() | Duration.t(), step :: pos_integer | neg_integer) ::
144154
Date.Range.t()
145155
def range(%{calendar: calendar} = first, %{calendar: calendar} = last, step)
146156
when is_integer(step) and step != 0 do
@@ -149,6 +159,11 @@ defmodule Date do
149159
range(first, first_days, last, last_days, calendar, step)
150160
end
151161

162+
def range(%{calendar: calendar} = first, %Duration{} = duration, step) do
163+
last = shift(first, duration)
164+
range(first, last, step)
165+
end
166+
152167
def range(
153168
%{calendar: _, year: _, month: _, day: _} = first,
154169
%{calendar: _, year: _, month: _, day: _} = last,

lib/elixir/test/elixir/calendar/date_range_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ defmodule Date.RangeTest do
66

77
@asc_range Date.range(~D[2000-01-01], ~D[2001-01-01])
88
@asc_range_2 Date.range(~D[2000-01-01], ~D[2001-01-01], 2)
9+
@asc_range_duration Date.range(~D[2000-01-01], Duration.new!(year: 1))
10+
@asc_range_duration_2 Date.range(~D[2000-01-01], Duration.new!(year: 1), 2)
911
@desc_range Date.range(~D[2001-01-01], ~D[2000-01-01], -1)
1012
@desc_range_2 Date.range(~D[2001-01-01], ~D[2000-01-01], -2)
13+
@desc_range_duration Date.range(~D[2001-01-01], Duration.new!(year: -1))
14+
@desc_range_duration_2 Date.range(~D[2001-01-01], Duration.new!(year: -1), 2)
1115
@empty_range Date.range(~D[2001-01-01], ~D[2000-01-01], 1)
1216

1317
describe "Enum.member?/2" do
@@ -20,6 +24,9 @@ defmodule Date.RangeTest do
2024

2125
assert Enum.member?(@asc_range_2, ~D[2000-01-03])
2226
refute Enum.member?(@asc_range_2, ~D[2000-01-02])
27+
28+
assert Enum.member?(@asc_range_duration, ~D[2000-01-03])
29+
refute Enum.member?(@asc_range_duration_2, ~D[2000-01-02])
2330
end
2431

2532
test "for descending range" do
@@ -31,6 +38,9 @@ defmodule Date.RangeTest do
3138

3239
assert Enum.member?(@desc_range_2, ~D[2000-12-30])
3340
refute Enum.member?(@desc_range_2, ~D[2000-12-29])
41+
42+
assert Enum.member?(@desc_range_duration, ~D[2000-12-30])
43+
refute Enum.member?(@desc_range_duration_2, ~D[2000-12-29])
3444
end
3545

3646
test "empty range" do
@@ -109,6 +119,18 @@ defmodule Date.RangeTest do
109119
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]]
110120
end
111121

122+
test "works with durations" do
123+
range = Date.range(~D[2000-01-01], Duration.new!(day: 1))
124+
assert range.first == ~D[2000-01-01]
125+
assert range.last == ~D[2000-01-02]
126+
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-02]]
127+
128+
range = Date.range(~D[2000-01-01], Duration.new!(day: 2), 2)
129+
assert range.first == ~D[2000-01-01]
130+
assert range.last == ~D[2000-01-03]
131+
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]]
132+
end
133+
112134
test "both dates must have matching calendars" do
113135
first = ~D[2000-01-01]
114136
last = Calendar.Holocene.date(12001, 1, 1)

0 commit comments

Comments
 (0)