Skip to content

Commit 7589754

Browse files
authored
Optimize parsing microseconds and offset in calendar (#14169)
1 parent 12b2004 commit 7589754

File tree

1 file changed

+35
-29
lines changed

1 file changed

+35
-29
lines changed

lib/elixir/lib/calendar/iso.ex

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,15 +1279,16 @@ defmodule Calendar.ISO do
12791279
def microseconds_to_iodata(microsecond, 6), do: zero_pad(microsecond, 6)
12801280

12811281
def microseconds_to_iodata(microsecond, precision) do
1282-
num = div(microsecond, div_factor(precision))
1282+
num = div(microsecond, scale_factor(precision))
12831283
zero_pad(num, precision)
12841284
end
12851285

1286-
defp div_factor(1), do: 100_000
1287-
defp div_factor(2), do: 10_000
1288-
defp div_factor(3), do: 1_000
1289-
defp div_factor(4), do: 100
1290-
defp div_factor(5), do: 10
1286+
defp scale_factor(1), do: 100_000
1287+
defp scale_factor(2), do: 10_000
1288+
defp scale_factor(3), do: 1_000
1289+
defp scale_factor(4), do: 100
1290+
defp scale_factor(5), do: 10
1291+
defp scale_factor(6), do: 1
12911292

12921293
defp time_to_iodata_format(hour, minute, second, :extended) do
12931294
[zero_pad(hour, 2), ?:, zero_pad(minute, 2), ?: | zero_pad(second, 2)]
@@ -1988,16 +1989,13 @@ defmodule Calendar.ISO do
19881989
end
19891990

19901991
defp parse_microsecond("." <> rest) do
1991-
case parse_microsecond(rest, 0, "") do
1992-
{"", 0, _} ->
1992+
case parse_microsecond(rest, 0, []) do
1993+
{[], 0, _} ->
19931994
:error
19941995

1995-
{microsecond, precision, rest} when precision in 1..6 ->
1996-
pad = String.duplicate("0", 6 - byte_size(microsecond))
1997-
{{String.to_integer(microsecond <> pad), precision}, rest}
1998-
1999-
{microsecond, _precision, rest} ->
2000-
{{String.to_integer(binary_part(microsecond, 0, 6)), 6}, rest}
1996+
{microsecond, precision, rest} ->
1997+
scale = scale_factor(precision)
1998+
{{:erlang.list_to_integer(microsecond) * scale, precision}, rest}
20011999
end
20022000
end
20032001

@@ -2009,34 +2007,42 @@ defmodule Calendar.ISO do
20092007
{{0, 0}, rest}
20102008
end
20112009

2010+
defp parse_microsecond(<<head, tail::binary>>, 6, acc) when head in ?0..?9,
2011+
do: parse_microsecond(tail, 6, acc)
2012+
20122013
defp parse_microsecond(<<head, tail::binary>>, precision, acc) when head in ?0..?9,
2013-
do: parse_microsecond(tail, precision + 1, <<acc::binary, head>>)
2014+
do: parse_microsecond(tail, precision + 1, [head | acc])
20142015

2015-
defp parse_microsecond(rest, precision, acc), do: {acc, precision, rest}
2016+
defp parse_microsecond(rest, precision, acc) do
2017+
{:lists.reverse(acc), precision, rest}
2018+
end
20162019

20172020
defp parse_offset(""), do: {nil, ""}
20182021
defp parse_offset("Z"), do: {0, ""}
20192022
defp parse_offset("-00:00"), do: :error
20202023

2021-
defp parse_offset(<<?+, hour::2-bytes, ?:, min::2-bytes, rest::binary>>),
2022-
do: parse_offset(1, hour, min, rest)
2024+
defp parse_offset(<<?+, h1, h2, ?:, m1, m2, rest::binary>>),
2025+
do: parse_offset(1, h1, h2, m1, m2, rest)
20232026

2024-
defp parse_offset(<<?-, hour::2-bytes, ?:, min::2-bytes, rest::binary>>),
2025-
do: parse_offset(-1, hour, min, rest)
2027+
defp parse_offset(<<?-, h1, h2, ?:, m1, m2, rest::binary>>),
2028+
do: parse_offset(-1, h1, h2, m1, m2, rest)
20262029

2027-
defp parse_offset(<<?+, hour::2-bytes, min::2-bytes, rest::binary>>),
2028-
do: parse_offset(1, hour, min, rest)
2030+
defp parse_offset(<<?+, h1, h2, m1, m2, rest::binary>>),
2031+
do: parse_offset(1, h1, h2, m1, m2, rest)
20292032

2030-
defp parse_offset(<<?-, hour::2-bytes, min::2-bytes, rest::binary>>),
2031-
do: parse_offset(-1, hour, min, rest)
2033+
defp parse_offset(<<?-, h1, h2, m1, m2, rest::binary>>),
2034+
do: parse_offset(-1, h1, h2, m1, m2, rest)
20322035

2033-
defp parse_offset(<<?+, hour::2-bytes, rest::binary>>), do: parse_offset(1, hour, "00", rest)
2034-
defp parse_offset(<<?-, hour::2-bytes, rest::binary>>), do: parse_offset(-1, hour, "00", rest)
2036+
defp parse_offset(<<?+, h1, h2, rest::binary>>), do: parse_offset(1, h1, h2, ?0, ?0, rest)
2037+
defp parse_offset(<<?-, h1, h2, rest::binary>>), do: parse_offset(-1, h1, h2, ?0, ?0, rest)
20352038
defp parse_offset(_), do: :error
20362039

2037-
defp parse_offset(sign, hour, min, rest) do
2038-
with {hour, ""} when hour < 24 <- Integer.parse(hour),
2039-
{min, ""} when min < 60 <- Integer.parse(min) do
2040+
defp parse_offset(sign, h1, h2, m1, m2, rest) do
2041+
with true <- h1 in ?0..?2 and h2 in ?0..?9,
2042+
true <- m1 in ?0..?5 and m2 in ?0..?9,
2043+
hour = (h1 - ?0) * 10 + h2 - ?0,
2044+
min = (m1 - ?0) * 10 + m2 - ?0,
2045+
true <- hour < 24 do
20402046
{(hour * 60 + min) * 60 * sign, rest}
20412047
else
20422048
_ -> :error

0 commit comments

Comments
 (0)