Skip to content

Commit b15de1c

Browse files
committed
Revert "Support Duration in Date.range/3 (#14172)"
There is some ambiguity if the duration represents the end date or the step, so it is best to be explicit about it. This reverts commit 8deaaf4.
1 parent 6613193 commit b15de1c

File tree

2 files changed

+10
-111
lines changed

2 files changed

+10
-111
lines changed

lib/elixir/lib/calendar/date.ex

+5-58
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,6 @@ defmodule Date do
6969
calendar: Calendar.calendar()
7070
}
7171

72-
@typedoc "A duration unit expressed as a tuple."
73-
@typedoc since: "1.19.0"
74-
@type duration_unit_pair ::
75-
{:year, integer} | {:month, integer} | {:week, integer} | {:day, integer}
76-
7772
@doc """
7873
Returns a range of dates.
7974
@@ -89,20 +84,6 @@ defmodule Date do
8984
iex> Date.range(~D[1999-01-01], ~D[2000-01-01])
9085
Date.range(~D[1999-01-01], ~D[2000-01-01])
9186
92-
A range may also be built from a `Date` and a `Duration`
93-
(also expressed as a keyword list of `t:duration_unit_pair/0`):
94-
95-
iex> Date.range(~D[1999-01-01], Duration.new!(year: 1))
96-
Date.range(~D[1999-01-01], ~D[2000-01-01])
97-
iex> Date.range(~D[1999-01-01], year: 1)
98-
Date.range(~D[1999-01-01], ~D[2000-01-01])
99-
100-
> #### Durations {: .warning}
101-
>
102-
> Support for expressing `last` as a [`Duration`](`t:Duration.t/0`) or
103-
> keyword list of `t:duration_unit_pair/0`s was introduced in
104-
> v1.19.0.
105-
10687
A range of dates implements the `Enumerable` protocol, which means
10788
functions in the `Enum` module can be used to work with
10889
ranges:
@@ -119,11 +100,7 @@ defmodule Date do
119100
120101
"""
121102
@doc since: "1.5.0"
122-
@spec range(
123-
first :: Calendar.date(),
124-
last_or_duration :: Calendar.date() | Duration.t() | [duration_unit_pair]
125-
) ::
126-
Date.Range.t()
103+
@spec range(Calendar.date(), Calendar.date()) :: Date.Range.t()
127104
def range(%{calendar: calendar} = first, %{calendar: calendar} = last) do
128105
{first_days, _} = to_iso_days(first)
129106
{last_days, _} = to_iso_days(last)
@@ -146,16 +123,6 @@ defmodule Date do
146123
raise ArgumentError, "both dates must have matching calendars"
147124
end
148125

149-
def range(%{calendar: _} = first, %Duration{} = duration) do
150-
last = shift(first, duration)
151-
range(first, last)
152-
end
153-
154-
def range(%{calendar: _} = first, duration) when is_list(duration) do
155-
last = shift(first, duration)
156-
range(first, last)
157-
end
158-
159126
@doc """
160127
Returns a range of dates with a step.
161128
@@ -173,11 +140,8 @@ defmodule Date do
173140
174141
"""
175142
@doc since: "1.12.0"
176-
@spec range(
177-
first :: Calendar.date(),
178-
last_or_duration :: Calendar.date() | Duration.t() | [duration_unit_pair],
179-
step :: pos_integer | neg_integer
180-
) :: Date.Range.t()
143+
@spec range(Calendar.date(), Calendar.date(), step :: pos_integer | neg_integer) ::
144+
Date.Range.t()
181145
def range(%{calendar: calendar} = first, %{calendar: calendar} = last, step)
182146
when is_integer(step) and step != 0 do
183147
{first_days, _} = to_iso_days(first)
@@ -195,24 +159,6 @@ defmodule Date do
195159
"non-zero integer, got: #{inspect(first)}, #{inspect(last)}, #{step}"
196160
end
197161

198-
def range(%{calendar: _} = first, %Duration{} = duration, step)
199-
when is_integer(step) and step != 0 do
200-
last = shift(first, duration)
201-
range(first, last, step)
202-
end
203-
204-
def range(%{calendar: _} = first, duration, step)
205-
when is_list(duration) and is_integer(step) and step != 0 do
206-
last = shift(first, duration)
207-
range(first, last, step)
208-
end
209-
210-
def range(%{calendar: _} = first, last, step) do
211-
raise ArgumentError,
212-
"expected a date or duration as second argument and the step must be a " <>
213-
"non-zero integer, got: #{inspect(first)}, #{inspect(last)}, #{step}"
214-
end
215-
216162
defp range(first, first_days, last, last_days, calendar, step) do
217163
%Date.Range{
218164
first: %Date{calendar: calendar, year: first.year, month: first.month, day: first.day},
@@ -849,7 +795,8 @@ defmodule Date do
849795
850796
"""
851797
@doc since: "1.17.0"
852-
@spec shift(Calendar.date(), Duration.t() | [duration_unit_pair]) :: t
798+
@spec shift(Calendar.date(), Duration.t() | [unit_pair]) :: t
799+
when unit_pair: {:year, integer} | {:month, integer} | {:week, integer} | {:day, integer}
853800
def shift(%{calendar: calendar} = date, duration) do
854801
%{year: year, month: month, day: day} = date
855802
{year, month, day} = calendar.shift_date(year, month, day, __duration__!(duration))

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

+5-53
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@ 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)
119
@desc_range Date.range(~D[2001-01-01], ~D[2000-01-01], -1)
1210
@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), -1)
14-
@desc_range_duration_2 Date.range(~D[2001-01-01], Duration.new!(year: -1), 2)
1511
@empty_range Date.range(~D[2001-01-01], ~D[2000-01-01], 1)
1612

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

2521
assert Enum.member?(@asc_range_2, ~D[2000-01-03])
2622
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])
3023
end
3124

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

3932
assert Enum.member?(@desc_range_2, ~D[2000-12-30])
4033
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])
4434
end
4535

4636
test "empty range" do
@@ -119,30 +109,6 @@ defmodule Date.RangeTest do
119109
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]]
120110
end
121111

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-
134-
test "accepts durations as keyword list" do
135-
range = Date.range(~D[2000-01-01], day: 1)
136-
assert range.first == ~D[2000-01-01]
137-
assert range.last == ~D[2000-01-02]
138-
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-02]]
139-
140-
range = Date.range(~D[2000-01-01], [day: 2], 2)
141-
assert range.first == ~D[2000-01-01]
142-
assert range.last == ~D[2000-01-03]
143-
assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]]
144-
end
145-
146112
test "both dates must have matching calendars" do
147113
first = ~D[2000-01-01]
148114
last = Calendar.Holocene.date(12001, 1, 1)
@@ -163,35 +129,21 @@ defmodule Date.RangeTest do
163129
end
164130

165131
test "step is a non-zero integer" do
132+
step = 1.0
166133
message = ~r"the step must be a non-zero integer"
167134

168135
assert_raise ArgumentError, message, fn ->
169-
Date.range(~D[2000-01-01], ~D[2000-01-31], 1.0)
170-
end
171-
172-
assert_raise ArgumentError, message, fn ->
173-
Date.range(~D[2000-01-01], [month: 1], 1.0)
136+
Date.range(~D[2000-01-01], ~D[2000-01-31], step)
174137
end
175138

176-
assert_raise ArgumentError, message, fn ->
177-
Date.range(~D[2000-01-01], ~D[2000-01-31], 0)
178-
end
139+
step = 0
140+
message = ~r"the step must be a non-zero integer"
179141

180142
assert_raise ArgumentError, message, fn ->
181-
Date.range(~D[2000-01-01], [month: 1], 0)
143+
Date.range(~D[2000-01-01], ~D[2000-01-31], step)
182144
end
183145
end
184146

185-
test "warns when inferring a negative step" do
186-
{result, captured} =
187-
ExUnit.CaptureIO.with_io(:stderr, fn ->
188-
Date.range(~D[2001-01-01], Duration.new!(year: -1))
189-
end)
190-
191-
assert result == Date.range(~D[2001-01-01], ~D[2000-01-01], -1)
192-
assert captured =~ "negative range was inferred for Date.range/2"
193-
end
194-
195147
describe "old date ranges" do
196148
test "inspect" do
197149
asc = %{

0 commit comments

Comments
 (0)