From b15de1cad66e249fe71f14d4696e2abd5933f60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 20 Jan 2025 11:32:33 +0100 Subject: [PATCH] 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 8deaaf4117fef24f516c12dc40989b9772a6d763. --- lib/elixir/lib/calendar/date.ex | 63 ++----------------- .../test/elixir/calendar/date_range_test.exs | 58 ++--------------- 2 files changed, 10 insertions(+), 111 deletions(-) diff --git a/lib/elixir/lib/calendar/date.ex b/lib/elixir/lib/calendar/date.ex index 4886b9f279d..854c1c42ee8 100644 --- a/lib/elixir/lib/calendar/date.ex +++ b/lib/elixir/lib/calendar/date.ex @@ -69,11 +69,6 @@ defmodule Date do calendar: Calendar.calendar() } - @typedoc "A duration unit expressed as a tuple." - @typedoc since: "1.19.0" - @type duration_unit_pair :: - {:year, integer} | {:month, integer} | {:week, integer} | {:day, integer} - @doc """ Returns a range of dates. @@ -89,20 +84,6 @@ defmodule Date do iex> Date.range(~D[1999-01-01], ~D[2000-01-01]) Date.range(~D[1999-01-01], ~D[2000-01-01]) - A range may also be built from a `Date` and a `Duration` - (also expressed as a keyword list of `t:duration_unit_pair/0`): - - iex> Date.range(~D[1999-01-01], Duration.new!(year: 1)) - Date.range(~D[1999-01-01], ~D[2000-01-01]) - iex> Date.range(~D[1999-01-01], year: 1) - Date.range(~D[1999-01-01], ~D[2000-01-01]) - - > #### Durations {: .warning} - > - > Support for expressing `last` as a [`Duration`](`t:Duration.t/0`) or - > keyword list of `t:duration_unit_pair/0`s was introduced in - > v1.19.0. - A range of dates implements the `Enumerable` protocol, which means functions in the `Enum` module can be used to work with ranges: @@ -119,11 +100,7 @@ defmodule Date do """ @doc since: "1.5.0" - @spec range( - first :: Calendar.date(), - last_or_duration :: Calendar.date() | Duration.t() | [duration_unit_pair] - ) :: - Date.Range.t() + @spec range(Calendar.date(), Calendar.date()) :: Date.Range.t() def range(%{calendar: calendar} = first, %{calendar: calendar} = last) do {first_days, _} = to_iso_days(first) {last_days, _} = to_iso_days(last) @@ -146,16 +123,6 @@ defmodule Date do raise ArgumentError, "both dates must have matching calendars" end - def range(%{calendar: _} = first, %Duration{} = duration) do - last = shift(first, duration) - range(first, last) - end - - def range(%{calendar: _} = first, duration) when is_list(duration) do - last = shift(first, duration) - range(first, last) - end - @doc """ Returns a range of dates with a step. @@ -173,11 +140,8 @@ defmodule Date do """ @doc since: "1.12.0" - @spec range( - first :: Calendar.date(), - last_or_duration :: Calendar.date() | Duration.t() | [duration_unit_pair], - step :: pos_integer | neg_integer - ) :: Date.Range.t() + @spec range(Calendar.date(), Calendar.date(), step :: pos_integer | neg_integer) :: + Date.Range.t() def range(%{calendar: calendar} = first, %{calendar: calendar} = last, step) when is_integer(step) and step != 0 do {first_days, _} = to_iso_days(first) @@ -195,24 +159,6 @@ defmodule Date do "non-zero integer, got: #{inspect(first)}, #{inspect(last)}, #{step}" end - def range(%{calendar: _} = first, %Duration{} = duration, step) - when is_integer(step) and step != 0 do - last = shift(first, duration) - range(first, last, step) - end - - def range(%{calendar: _} = first, duration, step) - when is_list(duration) and is_integer(step) and step != 0 do - last = shift(first, duration) - range(first, last, step) - end - - def range(%{calendar: _} = first, last, step) do - raise ArgumentError, - "expected a date or duration as second argument and the step must be a " <> - "non-zero integer, got: #{inspect(first)}, #{inspect(last)}, #{step}" - end - defp range(first, first_days, last, last_days, calendar, step) do %Date.Range{ first: %Date{calendar: calendar, year: first.year, month: first.month, day: first.day}, @@ -849,7 +795,8 @@ defmodule Date do """ @doc since: "1.17.0" - @spec shift(Calendar.date(), Duration.t() | [duration_unit_pair]) :: t + @spec shift(Calendar.date(), Duration.t() | [unit_pair]) :: t + when unit_pair: {:year, integer} | {:month, integer} | {:week, integer} | {:day, integer} def shift(%{calendar: calendar} = date, duration) do %{year: year, month: month, day: day} = date {year, month, day} = calendar.shift_date(year, month, day, __duration__!(duration)) diff --git a/lib/elixir/test/elixir/calendar/date_range_test.exs b/lib/elixir/test/elixir/calendar/date_range_test.exs index 009752542ad..77f4c5b0476 100644 --- a/lib/elixir/test/elixir/calendar/date_range_test.exs +++ b/lib/elixir/test/elixir/calendar/date_range_test.exs @@ -6,12 +6,8 @@ defmodule Date.RangeTest do @asc_range Date.range(~D[2000-01-01], ~D[2001-01-01]) @asc_range_2 Date.range(~D[2000-01-01], ~D[2001-01-01], 2) - @asc_range_duration Date.range(~D[2000-01-01], Duration.new!(year: 1)) - @asc_range_duration_2 Date.range(~D[2000-01-01], Duration.new!(year: 1), 2) @desc_range Date.range(~D[2001-01-01], ~D[2000-01-01], -1) @desc_range_2 Date.range(~D[2001-01-01], ~D[2000-01-01], -2) - @desc_range_duration Date.range(~D[2001-01-01], Duration.new!(year: -1), -1) - @desc_range_duration_2 Date.range(~D[2001-01-01], Duration.new!(year: -1), 2) @empty_range Date.range(~D[2001-01-01], ~D[2000-01-01], 1) describe "Enum.member?/2" do @@ -24,9 +20,6 @@ defmodule Date.RangeTest do assert Enum.member?(@asc_range_2, ~D[2000-01-03]) refute Enum.member?(@asc_range_2, ~D[2000-01-02]) - - assert Enum.member?(@asc_range_duration, ~D[2000-01-03]) - refute Enum.member?(@asc_range_duration_2, ~D[2000-01-02]) end test "for descending range" do @@ -38,9 +31,6 @@ defmodule Date.RangeTest do assert Enum.member?(@desc_range_2, ~D[2000-12-30]) refute Enum.member?(@desc_range_2, ~D[2000-12-29]) - - assert Enum.member?(@desc_range_duration, ~D[2000-12-30]) - refute Enum.member?(@desc_range_duration_2, ~D[2000-12-29]) end test "empty range" do @@ -119,30 +109,6 @@ defmodule Date.RangeTest do assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]] end - test "works with durations" do - range = Date.range(~D[2000-01-01], Duration.new!(day: 1)) - assert range.first == ~D[2000-01-01] - assert range.last == ~D[2000-01-02] - assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-02]] - - range = Date.range(~D[2000-01-01], Duration.new!(day: 2), 2) - assert range.first == ~D[2000-01-01] - assert range.last == ~D[2000-01-03] - assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]] - end - - test "accepts durations as keyword list" do - range = Date.range(~D[2000-01-01], day: 1) - assert range.first == ~D[2000-01-01] - assert range.last == ~D[2000-01-02] - assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-02]] - - range = Date.range(~D[2000-01-01], [day: 2], 2) - assert range.first == ~D[2000-01-01] - assert range.last == ~D[2000-01-03] - assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]] - end - test "both dates must have matching calendars" do first = ~D[2000-01-01] last = Calendar.Holocene.date(12001, 1, 1) @@ -163,35 +129,21 @@ defmodule Date.RangeTest do end test "step is a non-zero integer" do + step = 1.0 message = ~r"the step must be a non-zero integer" assert_raise ArgumentError, message, fn -> - Date.range(~D[2000-01-01], ~D[2000-01-31], 1.0) - end - - assert_raise ArgumentError, message, fn -> - Date.range(~D[2000-01-01], [month: 1], 1.0) + Date.range(~D[2000-01-01], ~D[2000-01-31], step) end - assert_raise ArgumentError, message, fn -> - Date.range(~D[2000-01-01], ~D[2000-01-31], 0) - end + step = 0 + message = ~r"the step must be a non-zero integer" assert_raise ArgumentError, message, fn -> - Date.range(~D[2000-01-01], [month: 1], 0) + Date.range(~D[2000-01-01], ~D[2000-01-31], step) end end - test "warns when inferring a negative step" do - {result, captured} = - ExUnit.CaptureIO.with_io(:stderr, fn -> - Date.range(~D[2001-01-01], Duration.new!(year: -1)) - end) - - assert result == Date.range(~D[2001-01-01], ~D[2000-01-01], -1) - assert captured =~ "negative range was inferred for Date.range/2" - end - describe "old date ranges" do test "inspect" do asc = %{