diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 5740cc31272..183a1573200 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1,3 +1,11 @@ +defmodule Ascii do + defmacro int(x) do + quote do + <<3::4, unquote(x)::4>> + end + end +end + defmodule Calendar.ISO do @moduledoc """ The default calendar implementation, a Gregorian calendar following ISO 8601. @@ -200,18 +208,20 @@ defmodule Calendar.ISO do # on ~D[0001-01-01] which is 366 days later. @iso_epoch 366 + import Ascii + [match_basic_date, match_ext_date, guard_date, read_date] = quote do [ - <>, - <>, - y1 >= ?0 and y1 <= ?9 and y2 >= ?0 and y2 <= ?9 and y3 >= ?0 and y3 <= ?9 and y4 >= ?0 and - y4 <= ?9 and m1 >= ?0 and m1 <= ?9 and m2 >= ?0 and m2 <= ?9 and d1 >= ?0 and d1 <= ?9 and - d2 >= ?0 and d2 <= ?9, + <>, + <>, + y1 <= 9 and y2 <= 9 and y3 <= 9 and y4 <= 9 and m1 <= 9 and m2 <= 9 and d1 <= 9 and + d2 <= 9, { - (y1 - ?0) * 1000 + (y2 - ?0) * 100 + (y3 - ?0) * 10 + (y4 - ?0), - (m1 - ?0) * 10 + (m2 - ?0), - (d1 - ?0) * 10 + (d2 - ?0) + y1 * 1000 + y2 * 100 + y3 * 10 + y4, + m1 * 10 + m2, + d1 * 10 + d2 } ] end @@ -219,14 +229,13 @@ defmodule Calendar.ISO do [match_basic_time, match_ext_time, guard_time, read_time] = quote do [ - <>, - <>, - h1 >= ?0 and h1 <= ?9 and h2 >= ?0 and h2 <= ?9 and i1 >= ?0 and i1 <= ?9 and i2 >= ?0 and - i2 <= ?9 and s1 >= ?0 and s1 <= ?9 and s2 >= ?0 and s2 <= ?9, + <>, + <>, + h1 <= 9 and h2 <= 9 and i1 <= 9 and i2 <= 9 and s1 <= 9 and s2 <= 9, { - (h1 - ?0) * 10 + (h2 - ?0), - (i1 - ?0) * 10 + (i2 - ?0), - (s1 - ?0) * 10 + (s2 - ?0) + h1 * 10 + h2, + i1 * 10 + i2, + s1 * 10 + s2 } ] end @@ -2021,34 +2030,38 @@ defmodule Calendar.ISO do defp parse_offset("Z"), do: {0, ""} defp parse_offset("-00:00"), do: :error - defp parse_offset(<>), + defp parse_offset(<>), do: parse_offset(1, h1, h2, m1, m2, rest) - defp parse_offset(<>), + defp parse_offset(<>), do: parse_offset(-1, h1, h2, m1, m2, rest) - defp parse_offset(<>), + defp parse_offset(<>), do: parse_offset(1, h1, h2, m1, m2, rest) - defp parse_offset(<>), + defp parse_offset(<>), do: parse_offset(-1, h1, h2, m1, m2, rest) - defp parse_offset(<>), do: parse_offset(1, h1, h2, ?0, ?0, rest) - defp parse_offset(<>), do: parse_offset(-1, h1, h2, ?0, ?0, rest) + defp parse_offset(<>), + do: parse_offset(1, h1, h2, 0, 0, rest) + + defp parse_offset(<>), + do: parse_offset(-1, h1, h2, 0, 0, rest) + defp parse_offset(_), do: :error - defp parse_offset(sign, h1, h2, m1, m2, rest) do - with true <- h1 in ?0..?2 and h2 in ?0..?9, - true <- m1 in ?0..?5 and m2 in ?0..?9, - hour = (h1 - ?0) * 10 + h2 - ?0, - min = (m1 - ?0) * 10 + m2 - ?0, - true <- hour < 24 do + defp parse_offset(sign, h1, h2, m1, m2, rest) + when h2 < 10 and m1 < 6 and m2 < 10 do + with hour when hour < 24 <- h1 * 10 + h2, + min = m1 * 10 + m2 do {(hour * 60 + min) * 60 * sign, rest} else _ -> :error end end + defp parse_offset(_, _, _, _, _, _), do: :error + @doc false def gregorian_seconds_to_iso_days(seconds, microsecond) do {days, rest_seconds} = div_rem(seconds, @seconds_per_day)