diff --git a/lib/elixir/lib/calendar/date.ex b/lib/elixir/lib/calendar/date.ex index 725fa861ec6..a14d561f75f 100644 --- a/lib/elixir/lib/calendar/date.ex +++ b/lib/elixir/lib/calendar/date.ex @@ -1157,10 +1157,20 @@ defmodule Date do end defimpl Inspect do - def inspect(%{calendar: calendar, year: year, month: month, day: day}, _) do + def inspect(%{calendar: calendar, year: year, month: month, day: day}, _) + when year in -9999..9999 do "~D[" <> calendar.date_to_string(year, month, day) <> suffix(calendar) <> "]" end + def inspect(%{calendar: calendar, year: year, month: month, day: day}, _) + when calendar == Calendar.ISO do + "Date.new!(#{Integer.to_string(year)}, #{Integer.to_string(month)}, #{Integer.to_string(day)})" + end + + def inspect(%{calendar: calendar, year: year, month: month, day: day}, _) do + "Date.new!(#{Integer.to_string(year)}, #{Integer.to_string(month)}, #{Integer.to_string(day)}, #{inspect(calendar)})" + end + defp suffix(Calendar.ISO), do: "" defp suffix(calendar), do: " " <> inspect(calendar) end diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 351f48fe921..71cc83ad94e 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -230,9 +230,9 @@ defmodule Calendar.ISO do ] end - defguardp is_year(year) when year in -9999..9999 - defguardp is_year_BCE(year) when year in -9999..0 - defguardp is_year_CE(year) when year in 1..9999 + defguardp is_year(year) when is_integer(year) + defguardp is_year_BCE(year) when year <= 0 + defguardp is_year_CE(year) when year >= 1 defguardp is_month(month) when month in 1..12 defguardp is_day(day) when day in 1..31 defguardp is_hour(hour) when hour in 0..23 @@ -809,7 +809,7 @@ defmodule Calendar.ISO do # Converts count of days since 0000-01-01 to {year, month, day} tuple. @doc false - def date_from_iso_days(days) when days in -3_652_059..3_652_424 do + def date_from_iso_days(days) do {year, day_of_year} = days_to_year(days) extra_day = if leap_year?(year), do: 1, else: 0 {month, day_in_month} = year_day_to_year_date(extra_day, day_of_year) diff --git a/lib/elixir/test/elixir/calendar/date_test.exs b/lib/elixir/test/elixir/calendar/date_test.exs index d1a59c8a160..09c5969c855 100644 --- a/lib/elixir/test/elixir/calendar/date_test.exs +++ b/lib/elixir/test/elixir/calendar/date_test.exs @@ -42,6 +42,14 @@ defmodule DateTest do assert to_string(%{date | calendar: FakeCalendar}) == "1/1/2000" assert Date.to_string(%{date | calendar: FakeCalendar}) == "1/1/2000" + + date2 = Date.new!(5_874_897, 12, 31) + assert to_string(date2) == "5874897-12-31" + assert Date.to_string(date2) == "5874897-12-31" + assert Date.to_string(Map.from_struct(date2)) == "5874897-12-31" + + assert to_string(%{date2 | calendar: FakeCalendar}) == "31/12/5874897" + assert Date.to_string(%{date2 | calendar: FakeCalendar}) == "31/12/5874897" end test "inspect/1" do @@ -50,29 +58,56 @@ defmodule DateTest do date = %{~D[2000-01-01] | calendar: FakeCalendar} assert inspect(date) == "~D[1/1/2000 FakeCalendar]" + + assert inspect(Date.new!(5_874_897, 12, 31)) == "Date.new!(5874897, 12, 31)" + assert inspect(Date.new!(-5_874_897, 1, 1)) == "Date.new!(-5874897, 1, 1)" + + date2 = %{Date.new!(5_874_897, 12, 31) | calendar: FakeCalendar} + + assert inspect(%{date2 | calendar: FakeCalendar}) == + "Date.new!(5874897, 12, 31, FakeCalendar)" end test "compare/2" do date1 = ~D[-0001-12-30] date2 = ~D[-0001-12-31] date3 = ~D[0001-01-01] + date4 = Date.new!(5_874_897, 12, 31) + date5 = Date.new!(-4713, 1, 1) + assert Date.compare(date1, date1) == :eq assert Date.compare(date1, date2) == :lt assert Date.compare(date2, date1) == :gt assert Date.compare(date3, date3) == :eq assert Date.compare(date2, date3) == :lt assert Date.compare(date3, date2) == :gt + assert Date.compare(date4, date1) == :gt + assert Date.compare(date1, date4) == :lt + assert Date.compare(date4, date4) == :eq + assert Date.compare(date4, date5) == :gt + assert Date.compare(date5, date4) == :lt + assert Date.compare(date5, date5) == :eq end test "before?/2 and after?/2" do date1 = ~D[2022-11-01] date2 = ~D[2022-11-02] + date3 = Date.new!(5_874_897, 12, 31) + date4 = Date.new!(-4713, 1, 1) assert Date.before?(date1, date2) + assert Date.before?(date1, date3) + assert Date.before?(date4, date1) assert not Date.before?(date2, date1) + assert not Date.before?(date3, date1) + assert not Date.before?(date1, date4) assert Date.after?(date2, date1) + assert Date.after?(date3, date2) + assert Date.after?(date2, date4) assert not Date.after?(date1, date2) + assert not Date.after?(date2, date3) + assert not Date.after?(date4, date2) end test "compare/2 across calendars" do @@ -149,11 +184,7 @@ defmodule DateTest do test "add/2" do assert Date.add(~D[0000-01-01], 3_652_424) == ~D[9999-12-31] - - assert_raise FunctionClauseError, fn -> - Date.add(~D[0000-01-01], 3_652_425) - end - + assert Date.add(~D[0000-01-01], 3_652_425) == Date.new!(10000, 1, 1) assert Date.add(~D[0000-01-01], -1) == ~D[-0001-12-31] assert Date.add(~D[0000-01-01], -365) == ~D[-0001-01-01] assert Date.add(~D[0000-01-01], -366) == ~D[-0002-12-31] @@ -161,10 +192,8 @@ defmodule DateTest do assert Date.add(~D[0000-01-01], -(365 * 5)) == ~D[-0005-01-02] assert Date.add(~D[0000-01-01], -(365 * 100)) == ~D[-0100-01-25] assert Date.add(~D[0000-01-01], -3_652_059) == ~D[-9999-01-01] - - assert_raise FunctionClauseError, fn -> - Date.add(~D[0000-01-01], -3_652_060) - end + assert Date.add(~D[0000-01-01], -3_652_060) == Date.new!(-10000, 12, 31) + assert Date.add(Date.new!(5_874_897, 12, 31), 1) == Date.new!(5_874_898, 1, 1) end test "diff/2" do @@ -174,6 +203,9 @@ defmodule DateTest do assert Date.diff(~D[0000-01-01], ~D[-0001-01-01]) == 365 assert Date.diff(~D[-0003-01-01], ~D[-0004-01-01]) == 366 + assert Date.diff(Date.new!(5_874_898, 1, 1), Date.new!(5_874_897, 1, 1)) == 365 + assert Date.diff(Date.new!(5_874_905, 1, 1), Date.new!(5_874_904, 1, 1)) == 366 + date1 = ~D[2000-01-01] date2 = Calendar.Holocene.date(12000, 01, 14) assert Date.diff(date1, date2) == -13 @@ -194,6 +226,17 @@ defmodule DateTest do assert Date.shift(~D[2000-01-01], month: 12) == ~D[2001-01-01] assert Date.shift(~D[0000-01-01], day: 2, year: 1, month: 37) == ~D[0004-02-03] + assert Date.shift(Date.new!(5_874_904, 2, 29), day: -1) == Date.new!(5_874_904, 2, 28) + assert Date.shift(Date.new!(5_874_904, 2, 29), month: -2) == Date.new!(5_874_903, 12, 29) + assert Date.shift(Date.new!(5_874_904, 2, 29), week: -9) == Date.new!(5_874_903, 12, 28) + assert Date.shift(Date.new!(5_874_904, 2, 29), month: 1) == Date.new!(5_874_904, 3, 29) + assert Date.shift(Date.new!(5_874_904, 2, 29), year: -1) == Date.new!(5_874_903, 2, 28) + assert Date.shift(Date.new!(5_874_904, 2, 29), year: -4) == Date.new!(5_874_900, 2, 28) + assert Date.shift(Date.new!(5_874_904, 2, 29), year: 4) == Date.new!(5_874_908, 2, 29) + + assert Date.shift(Date.new!(5_874_904, 2, 29), day: 1, year: 4, month: 2) == + Date.new!(5_874_908, 4, 30) + assert_raise ArgumentError, "unsupported unit :second. Expected :year, :month, :week, :day", fn -> Date.shift(~D[2012-02-29], second: 86400) end diff --git a/lib/elixir/test/elixir/calendar/iso_test.exs b/lib/elixir/test/elixir/calendar/iso_test.exs index 25bc13fea8d..a3ce35c25b2 100644 --- a/lib/elixir/test/elixir/calendar/iso_test.exs +++ b/lib/elixir/test/elixir/calendar/iso_test.exs @@ -114,14 +114,6 @@ defmodule Calendar.ISOTest do random_positive_year = Enum.random(1..9999) assert Calendar.ISO.year_of_era(random_positive_year, 1, 1) == {random_positive_year, 1} - - assert_raise FunctionClauseError, fn -> - Calendar.ISO.year_of_era(10000, 1, 1) - end - - assert_raise FunctionClauseError, fn -> - Calendar.ISO.year_of_era(-10000, 12, 1) - end end defp iso_day_roundtrip(year, month, day) do