From 4f663406642a7f45d2946190cc12584569b5fb3a Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 13:50:46 +0100 Subject: [PATCH 01/10] dk_use_iodata_when_formatting_dates --- lib/elixir/lib/calendar/iso.ex | 128 +++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index aa18c26eec2..e4296cac27a 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1220,6 +1220,17 @@ defmodule Calendar.ISO do :basic | :extended ) :: String.t() def time_to_string( + hour, + minute, + second, + microsecond, + format \\ :extended + ) do + time_to_iodata(hour, minute, second, microsecond, format) + |> IO.iodata_to_binary() + end + + def time_to_iodata( hour, minute, second, @@ -1228,24 +1239,27 @@ defmodule Calendar.ISO do ) when is_hour(hour) and is_minute(minute) and is_second(second) and is_microsecond(ms_value, ms_precision) and format in [:basic, :extended] do - time_to_string_guarded(hour, minute, second, microsecond, format) + time_to_iodata_guarded(hour, minute, second, microsecond, format) end - defp time_to_string_guarded(hour, minute, second, {_, 0}, format) do - time_to_string_format(hour, minute, second, format) + defp time_to_iodata_guarded(hour, minute, second, {_, 0}, format) do + time_to_iodata_format(hour, minute, second, format) end - defp time_to_string_guarded(hour, minute, second, {microsecond, precision}, format) do - time_to_string_format(hour, minute, second, format) <> - "." <> (microsecond |> zero_pad(6) |> binary_part(0, precision)) + defp time_to_iodata_guarded(hour, minute, second, {microsecond, precision}, format) do + [ + time_to_iodata_format(hour, minute, second, format), + ".", + microsecond |> zero_pad(6) |> IO.iodata_to_binary() |> binary_part(0, precision) + ] end - defp time_to_string_format(hour, minute, second, :extended) do - zero_pad(hour, 2) <> ":" <> zero_pad(minute, 2) <> ":" <> zero_pad(second, 2) + defp time_to_iodata_format(hour, minute, second, :extended) do + [zero_pad(hour, 2), ":", zero_pad(minute, 2), ":", zero_pad(second, 2)] end - defp time_to_string_format(hour, minute, second, :basic) do - zero_pad(hour, 2) <> zero_pad(minute, 2) <> zero_pad(second, 2) + defp time_to_iodata_format(hour, minute, second, :basic) do + [zero_pad(hour, 2), zero_pad(minute, 2), zero_pad(second, 2)] end @doc """ @@ -1273,18 +1287,27 @@ defmodule Calendar.ISO do @doc since: "1.4.0" @spec date_to_string(year, month, day, :basic | :extended) :: String.t() @impl true - def date_to_string(year, month, day, format \\ :extended) + def date_to_string(year, month, day, format \\ :extended) do + date_to_iodata(year, month, day, format) + |> IO.iodata_to_binary() + end + + def date_to_iodata(year, month, day, format \\ :extended) when is_integer(year) and is_integer(month) and is_integer(day) and format in [:basic, :extended] do - date_to_string_guarded(year, month, day, format) + date_to_iodata_guarded(year, month, day, format) end - defp date_to_string_guarded(year, month, day, :extended) do - zero_pad(year, 4) <> "-" <> zero_pad(month, 2) <> "-" <> zero_pad(day, 2) + defp date_to_iodata_guarded(year, month, day, :extended) do + [zero_pad(year, 4), "-", zero_pad(month, 2), "-", zero_pad(day, 2)] end - defp date_to_string_guarded(year, month, day, :basic) do - zero_pad(year, 4) <> zero_pad(month, 2) <> zero_pad(day, 2) + defp date_to_iodata_guarded(year, month, day, :basic) do + [ + zero_pad(year, 4), + zero_pad(month, 2), + zero_pad(day, 2) + ] end @doc """ @@ -1327,8 +1350,34 @@ defmodule Calendar.ISO do microsecond, format \\ :extended ) do - date_to_string(year, month, day, format) <> - " " <> time_to_string(hour, minute, second, microsecond, format) + naive_datetime_to_iodata( + year, + month, + day, + hour, + minute, + second, + microsecond, + format + ) + |> IO.iodata_to_binary() + end + + def naive_datetime_to_iodata( + year, + month, + day, + hour, + minute, + second, + microsecond, + format \\ :extended + ) do + [ + date_to_iodata(year, month, day, format), + " ", + time_to_iodata(hour, minute, second, microsecond, format) + ] end @doc """ @@ -1397,17 +1446,27 @@ defmodule Calendar.ISO do ) when is_time_zone(time_zone) and is_zone_abbr(zone_abbr) and is_utc_offset(utc_offset) and is_std_offset(std_offset) do - date_to_string(year, month, day, format) <> - " " <> - time_to_string(hour, minute, second, microsecond, format) <> - offset_to_string(utc_offset, std_offset, time_zone, format) <> - zone_to_string(utc_offset, std_offset, zone_abbr, time_zone) + [ + date_to_iodata(year, month, day, format), + " ", + time_to_iodata(hour, minute, second, microsecond, format), + offset_to_iodata(utc_offset, std_offset, time_zone, format), + zone_to_iodata(utc_offset, std_offset, zone_abbr, time_zone) + ] + |> IO.iodata_to_binary() end @doc false def offset_to_string(0, 0, "Etc/UTC", _format), do: "Z" - def offset_to_string(utc, std, _zone, format) do + def offset_to_string(utc, std, zone, format) do + offset_to_iodata(utc, std, zone, format) + |> IO.iodata_to_binary() + end + + def offset_to_iodata(0, 0, "Etc/UTC", _format), do: "Z" + + def offset_to_iodata(utc, std, _zone, format) do total = utc + std second = abs(total) minute = second |> rem(3600) |> div(60) @@ -1416,15 +1475,15 @@ defmodule Calendar.ISO do end defp format_offset(total, hour, minute, :extended) do - sign(total) <> zero_pad(hour, 2) <> ":" <> zero_pad(minute, 2) + [sign(total), zero_pad(hour, 2), ":", zero_pad(minute, 2)] end defp format_offset(total, hour, minute, :basic) do - sign(total) <> zero_pad(hour, 2) <> zero_pad(minute, 2) + [sign(total), zero_pad(hour, 2), zero_pad(minute, 2)] end - defp zone_to_string(_, _, _, "Etc/UTC"), do: "" - defp zone_to_string(_, _, abbr, zone), do: " " <> abbr <> " " <> zone + defp zone_to_iodata(_, _, _, "Etc/UTC"), do: "" + defp zone_to_iodata(_, _, abbr, zone), do: [" ", abbr, " ", zone] @doc """ Determines if the date given is valid according to the proleptic Gregorian calendar. @@ -1490,11 +1549,20 @@ defmodule Calendar.ISO do defp zero_pad(val, count) when val >= 0 do num = Integer.to_string(val) - :binary.copy("0", max(count - byte_size(num), 0)) <> num + + case max(count - byte_size(num), 0) do + 0 -> num + 1 -> ["0", num] + 2 -> ["00", num] + 3 -> ["000", num] + 4 -> ["0000", num] + 5 -> ["00000", num] + 6 -> ["000000", num] + end end defp zero_pad(val, count) do - "-" <> zero_pad(-val, count) + ["-", zero_pad(-val, count)] end @doc """ From 621cef0af912d80c9c0792d4c3b3f0d0dc12c9b4 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 14:02:41 +0100 Subject: [PATCH 02/10] add datatime_to_iodata --- lib/elixir/lib/calendar/iso.ex | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index e4296cac27a..fa167ce8ebf 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1443,6 +1443,37 @@ defmodule Calendar.ISO do utc_offset, std_offset, format \\ :extended + ) do + datetime_to_iodata( + year, + month, + day, + hour, + minute, + second, + microsecond, + time_zone, + zone_abbr, + utc_offset, + std_offset, + format + ) + |> IO.iodata_to_binary() + end + + def datetime_to_iodata( + year, + month, + day, + hour, + minute, + second, + microsecond, + time_zone, + zone_abbr, + utc_offset, + std_offset, + format \\ :extended ) when is_time_zone(time_zone) and is_zone_abbr(zone_abbr) and is_utc_offset(utc_offset) and is_std_offset(std_offset) do @@ -1453,7 +1484,6 @@ defmodule Calendar.ISO do offset_to_iodata(utc_offset, std_offset, time_zone, format), zone_to_iodata(utc_offset, std_offset, zone_abbr, time_zone) ] - |> IO.iodata_to_binary() end @doc false From 9303f849335d01bebcef3775b951f919e0bdb610 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 19:28:58 +0100 Subject: [PATCH 03/10] optimize_microseconds_conversion --- lib/elixir/lib/calendar/iso.ex | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index fa167ce8ebf..74e52ff8f4b 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1250,10 +1250,24 @@ defmodule Calendar.ISO do [ time_to_iodata_format(hour, minute, second, format), ".", - microsecond |> zero_pad(6) |> IO.iodata_to_binary() |> binary_part(0, precision) + microseconds_to_iodata(microsecond, precision) ] end + defp microseconds_to_iodata(_microsecond, 0), do: [] + defp microseconds_to_iodata(microsecond, 6), do: zero_pad(microsecond, 6) + + defp microseconds_to_iodata(microsecond, precision) do + num = div(microsecond, div_factor(precision)) + zero_pad(num, precision) + end + + defp div_factor(1), do: 100_000 + defp div_factor(2), do: 10_000 + defp div_factor(3), do: 1_000 + defp div_factor(4), do: 100 + defp div_factor(5), do: 10 + defp time_to_iodata_format(hour, minute, second, :extended) do [zero_pad(hour, 2), ":", zero_pad(minute, 2), ":", zero_pad(second, 2)] end @@ -1577,7 +1591,7 @@ defmodule Calendar.ISO do defp sign(total) when total < 0, do: "-" defp sign(_), do: "+" - defp zero_pad(val, count) when val >= 0 do + defp zero_pad(val, count) when val >= 0 and count <= 6 do num = Integer.to_string(val) case max(count - byte_size(num), 0) do @@ -1587,7 +1601,6 @@ defmodule Calendar.ISO do 3 -> ["000", num] 4 -> ["0000", num] 5 -> ["00000", num] - 6 -> ["000000", num] end end From 75ed764bb6267c0b681a5951cac1b02471648a18 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 20:06:12 +0100 Subject: [PATCH 04/10] use integers instead of 1 byte strings --- lib/elixir/lib/calendar/iso.ex | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 74e52ff8f4b..9b7e9259731 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1249,7 +1249,7 @@ defmodule Calendar.ISO do defp time_to_iodata_guarded(hour, minute, second, {microsecond, precision}, format) do [ time_to_iodata_format(hour, minute, second, format), - ".", + ?., microseconds_to_iodata(microsecond, precision) ] end @@ -1269,7 +1269,7 @@ defmodule Calendar.ISO do defp div_factor(5), do: 10 defp time_to_iodata_format(hour, minute, second, :extended) do - [zero_pad(hour, 2), ":", zero_pad(minute, 2), ":", zero_pad(second, 2)] + [zero_pad(hour, 2), ?:, zero_pad(minute, 2), ?:, zero_pad(second, 2)] end defp time_to_iodata_format(hour, minute, second, :basic) do @@ -1313,15 +1313,11 @@ defmodule Calendar.ISO do end defp date_to_iodata_guarded(year, month, day, :extended) do - [zero_pad(year, 4), "-", zero_pad(month, 2), "-", zero_pad(day, 2)] + [zero_pad(year, 4), ?-, zero_pad(month, 2), ?-, zero_pad(day, 2)] end defp date_to_iodata_guarded(year, month, day, :basic) do - [ - zero_pad(year, 4), - zero_pad(month, 2), - zero_pad(day, 2) - ] + [zero_pad(year, 4), zero_pad(month, 2), zero_pad(day, 2)] end @doc """ @@ -1389,7 +1385,7 @@ defmodule Calendar.ISO do ) do [ date_to_iodata(year, month, day, format), - " ", + ?\s, time_to_iodata(hour, minute, second, microsecond, format) ] end @@ -1493,7 +1489,7 @@ defmodule Calendar.ISO do is_std_offset(std_offset) do [ date_to_iodata(year, month, day, format), - " ", + ?\s, time_to_iodata(hour, minute, second, microsecond, format), offset_to_iodata(utc_offset, std_offset, time_zone, format), zone_to_iodata(utc_offset, std_offset, zone_abbr, time_zone) @@ -1508,7 +1504,7 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end - def offset_to_iodata(0, 0, "Etc/UTC", _format), do: "Z" + def offset_to_iodata(0, 0, "Etc/UTC", _format), do: ?Z def offset_to_iodata(utc, std, _zone, format) do total = utc + std @@ -1519,15 +1515,15 @@ defmodule Calendar.ISO do end defp format_offset(total, hour, minute, :extended) do - [sign(total), zero_pad(hour, 2), ":", zero_pad(minute, 2)] + [sign(total), zero_pad(hour, 2), ?:, zero_pad(minute, 2)] end defp format_offset(total, hour, minute, :basic) do [sign(total), zero_pad(hour, 2), zero_pad(minute, 2)] end - defp zone_to_iodata(_, _, _, "Etc/UTC"), do: "" - defp zone_to_iodata(_, _, abbr, zone), do: [" ", abbr, " ", zone] + defp zone_to_iodata(_, _, _, "Etc/UTC"), do: [] + defp zone_to_iodata(_, _, abbr, zone), do: [?\s, abbr, ?\s, zone] @doc """ Determines if the date given is valid according to the proleptic Gregorian calendar. @@ -1588,8 +1584,8 @@ defmodule Calendar.ISO do {0, 1} end - defp sign(total) when total < 0, do: "-" - defp sign(_), do: "+" + defp sign(total) when total < 0, do: ?- + defp sign(_), do: ?+ defp zero_pad(val, count) when val >= 0 and count <= 6 do num = Integer.to_string(val) @@ -1605,7 +1601,7 @@ defmodule Calendar.ISO do end defp zero_pad(val, count) do - ["-", zero_pad(-val, count)] + [?-, zero_pad(-val, count)] end @doc """ From 6f63ca302f8652602acb65eb95df0358ebc472a9 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 20:28:14 +0100 Subject: [PATCH 05/10] add docs --- lib/elixir/lib/calendar/iso.ex | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 9b7e9259731..7dde118143d 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1230,6 +1230,18 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end + @doc """ + Converts the given time into a iodata. + + Loog at time_to_string/5 for more information + + ## Examples + + iex> Calendar.ISO.time_to_iodata(2, 2, 2, {2, 6}) + [[["0", "2"], 58, ["0", "2"], 58, ["0", "2"]], 46, ["00000", "2"]] + + """ + @doc since: "1.19.0" def time_to_iodata( hour, minute, @@ -1306,6 +1318,17 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end + @doc """ + Converts the given date into a iodata. + Look at date_to_string/4 for more information + + ## Examples + + iex> Calendar.ISO.date_to_iodata(2015, 2, 28) + ["2015", 45, ["0", "2"], 45, "28"] + """ + @doc since: "1.19.0" + @spec date_to_iodata(year, month, day, :basic | :extended) :: iodata def date_to_iodata(year, month, day, format \\ :extended) when is_integer(year) and is_integer(month) and is_integer(day) and format in [:basic, :extended] do @@ -1373,6 +1396,17 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end + @doc """ + Converts the given naive_datetime into a iodata. + Look at naive_datetime_to_iodata/8 for more information + + ## Examples + + iex> Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :basic) + [["2015", ["0", "2"], "28"], 32, [[["0", "1"], ["0", "2"], ["0", "3"]], 46, ["00000", "4"]]] + + """ + @doc since: "1.19.0" def naive_datetime_to_iodata( year, month, @@ -1471,6 +1505,18 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end + @doc """ + Converts the given datetime into a iodata. + Look at datetime_to_iodata/12 for more information + + ## Examples + + iex> time_zone = "Etc/UTC" + iex> Calendar.ISO.datetime_to_iodata(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, "UTC", 0, 0) + [["2017", 45, ["0", "8"], 45, ["0", "1"]], 32, [[["0", "1"], 58, ["0", "2"], 58, ["0", "3"]], 46, ["0000", "0"]], 90, []] + + """ + @doc since: "1.19.0" def datetime_to_iodata( year, month, @@ -1504,6 +1550,7 @@ defmodule Calendar.ISO do |> IO.iodata_to_binary() end + @doc false def offset_to_iodata(0, 0, "Etc/UTC", _format), do: ?Z def offset_to_iodata(utc, std, _zone, format) do From 7025133773767bc140e30602014946c32a51f6ba Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 20:29:40 +0100 Subject: [PATCH 06/10] typo --- lib/elixir/lib/calendar/iso.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 7dde118143d..607643cfd83 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1233,7 +1233,7 @@ defmodule Calendar.ISO do @doc """ Converts the given time into a iodata. - Loog at time_to_string/5 for more information + Look at time_to_string/5 for more information ## Examples From e091108e9a23980a07d553c6b735086be9c8bde1 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Mon, 30 Dec 2024 23:37:13 +0100 Subject: [PATCH 07/10] use improper lists, add missing spec, update tests --- lib/elixir/lib/calendar/iso.ex | 96 ++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 607643cfd83..cbeaaa3ac23 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1237,11 +1237,19 @@ defmodule Calendar.ISO do ## Examples - iex> Calendar.ISO.time_to_iodata(2, 2, 2, {2, 6}) - [[["0", "2"], 58, ["0", "2"], 58, ["0", "2"]], 46, ["00000", "2"]] + iex> data = Calendar.ISO.time_to_iodata(2, 2, 2, {2, 6}) + iex> IO.iodata_to_binary(data) + "02:02:02.000002" """ @doc since: "1.19.0" + @spec time_to_iodata( + Calendar.hour(), + Calendar.minute(), + Calendar.second(), + Calendar.microsecond(), + :basic | :extended + ) :: iodata def time_to_iodata( hour, minute, @@ -1261,15 +1269,16 @@ defmodule Calendar.ISO do defp time_to_iodata_guarded(hour, minute, second, {microsecond, precision}, format) do [ time_to_iodata_format(hour, minute, second, format), - ?., - microseconds_to_iodata(microsecond, precision) + ?. + | microseconds_to_iodata(microsecond, precision) ] end - defp microseconds_to_iodata(_microsecond, 0), do: [] - defp microseconds_to_iodata(microsecond, 6), do: zero_pad(microsecond, 6) + @doc false + def microseconds_to_iodata(_microsecond, 0), do: [] + def microseconds_to_iodata(microsecond, 6), do: zero_pad(microsecond, 6) - defp microseconds_to_iodata(microsecond, precision) do + def microseconds_to_iodata(microsecond, precision) do num = div(microsecond, div_factor(precision)) zero_pad(num, precision) end @@ -1281,11 +1290,11 @@ defmodule Calendar.ISO do defp div_factor(5), do: 10 defp time_to_iodata_format(hour, minute, second, :extended) do - [zero_pad(hour, 2), ?:, zero_pad(minute, 2), ?:, zero_pad(second, 2)] + [zero_pad(hour, 2), ?:, zero_pad(minute, 2), ?: | zero_pad(second, 2)] end defp time_to_iodata_format(hour, minute, second, :basic) do - [zero_pad(hour, 2), zero_pad(minute, 2), zero_pad(second, 2)] + [zero_pad(hour, 2), zero_pad(minute, 2) | zero_pad(second, 2)] end @doc """ @@ -1324,8 +1333,9 @@ defmodule Calendar.ISO do ## Examples - iex> Calendar.ISO.date_to_iodata(2015, 2, 28) - ["2015", 45, ["0", "2"], 45, "28"] + iex> data = Calendar.ISO.date_to_iodata(2015, 2, 28) + iex> IO.iodata_to_binary(data) + "2015-02-28" """ @doc since: "1.19.0" @spec date_to_iodata(year, month, day, :basic | :extended) :: iodata @@ -1336,11 +1346,11 @@ defmodule Calendar.ISO do end defp date_to_iodata_guarded(year, month, day, :extended) do - [zero_pad(year, 4), ?-, zero_pad(month, 2), ?-, zero_pad(day, 2)] + [zero_pad(year, 4), ?-, zero_pad(month, 2), ?- | zero_pad(day, 2)] end defp date_to_iodata_guarded(year, month, day, :basic) do - [zero_pad(year, 4), zero_pad(month, 2), zero_pad(day, 2)] + [zero_pad(year, 4), zero_pad(month, 2) | zero_pad(day, 2)] end @doc """ @@ -1402,11 +1412,26 @@ defmodule Calendar.ISO do ## Examples - iex> Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :basic) - [["2015", ["0", "2"], "28"], 32, [[["0", "1"], ["0", "2"], ["0", "3"]], 46, ["00000", "4"]]] + iex> data = Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :basic) + iex> IO.iodata_to_binary(data) + "20150228 010203.000004" + + iex> data = Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :extended) + iex> IO.iodata_to_binary(data) + "2015-02-28 01:02:03.000004" """ @doc since: "1.19.0" + @spec naive_datetime_to_string( + year, + month, + day, + Calendar.hour(), + Calendar.minute(), + Calendar.second(), + Calendar.microsecond(), + :basic | :extended + ) :: iodata def naive_datetime_to_iodata( year, month, @@ -1419,8 +1444,8 @@ defmodule Calendar.ISO do ) do [ date_to_iodata(year, month, day, format), - ?\s, - time_to_iodata(hour, minute, second, microsecond, format) + ?\s + | time_to_iodata(hour, minute, second, microsecond, format) ] end @@ -1512,11 +1537,26 @@ defmodule Calendar.ISO do ## Examples iex> time_zone = "Etc/UTC" - iex> Calendar.ISO.datetime_to_iodata(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, "UTC", 0, 0) - [["2017", 45, ["0", "8"], 45, ["0", "1"]], 32, [[["0", "1"], 58, ["0", "2"], 58, ["0", "3"]], 46, ["0000", "0"]], 90, []] + iex> data = Calendar.ISO.datetime_to_iodata(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, "UTC", 0, 0) + iex> IO.iodata_to_binary(data) + "2017-08-01 01:02:03.00000Z" """ @doc since: "1.19.0" + @spec datetime_to_iodata( + year, + month, + day, + Calendar.hour(), + Calendar.minute(), + Calendar.second(), + Calendar.microsecond(), + Calendar.time_zone(), + Calendar.zone_abbr(), + Calendar.utc_offset(), + Calendar.std_offset(), + :basic | :extended + ) :: iodata def datetime_to_iodata( year, month, @@ -1562,15 +1602,15 @@ defmodule Calendar.ISO do end defp format_offset(total, hour, minute, :extended) do - [sign(total), zero_pad(hour, 2), ?:, zero_pad(minute, 2)] + [sign(total), zero_pad(hour, 2), ?: | zero_pad(minute, 2)] end defp format_offset(total, hour, minute, :basic) do - [sign(total), zero_pad(hour, 2), zero_pad(minute, 2)] + [sign(total), zero_pad(hour, 2) | zero_pad(minute, 2)] end defp zone_to_iodata(_, _, _, "Etc/UTC"), do: [] - defp zone_to_iodata(_, _, abbr, zone), do: [?\s, abbr, ?\s, zone] + defp zone_to_iodata(_, _, abbr, zone), do: [?\s, abbr, ?\s | zone] @doc """ Determines if the date given is valid according to the proleptic Gregorian calendar. @@ -1639,16 +1679,16 @@ defmodule Calendar.ISO do case max(count - byte_size(num), 0) do 0 -> num - 1 -> ["0", num] - 2 -> ["00", num] - 3 -> ["000", num] - 4 -> ["0000", num] - 5 -> ["00000", num] + 1 -> ["0" | num] + 2 -> ["00" | num] + 3 -> ["000" | num] + 4 -> ["0000" | num] + 5 -> ["00000" | num] end end defp zero_pad(val, count) do - [?-, zero_pad(-val, count)] + [?- | zero_pad(-val, count)] end @doc """ From 09eb9bf0e92349ca4b822b93de4691ed7c68744a Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Tue, 31 Dec 2024 07:50:20 +0100 Subject: [PATCH 08/10] docs update --- lib/elixir/lib/calendar/iso.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index cbeaaa3ac23..c91b7d29378 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1233,7 +1233,7 @@ defmodule Calendar.ISO do @doc """ Converts the given time into a iodata. - Look at time_to_string/5 for more information + See time_to_string/5 for more information ## Examples @@ -1329,7 +1329,7 @@ defmodule Calendar.ISO do @doc """ Converts the given date into a iodata. - Look at date_to_string/4 for more information + See date_to_string/4 for more information ## Examples @@ -1408,7 +1408,7 @@ defmodule Calendar.ISO do @doc """ Converts the given naive_datetime into a iodata. - Look at naive_datetime_to_iodata/8 for more information + See naive_datetime_to_iodata/8 for more information ## Examples @@ -1532,7 +1532,7 @@ defmodule Calendar.ISO do @doc """ Converts the given datetime into a iodata. - Look at datetime_to_iodata/12 for more information + See datetime_to_iodata/12 for more information ## Examples From fbdf2355467139fe0b9bf1962974a09af4f38f38 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Tue, 31 Dec 2024 07:52:05 +0100 Subject: [PATCH 09/10] add newline --- lib/elixir/lib/calendar/iso.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index c91b7d29378..4367efa6861 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1329,6 +1329,7 @@ defmodule Calendar.ISO do @doc """ Converts the given date into a iodata. + See date_to_string/4 for more information ## Examples @@ -1408,6 +1409,7 @@ defmodule Calendar.ISO do @doc """ Converts the given naive_datetime into a iodata. + See naive_datetime_to_iodata/8 for more information ## Examples @@ -1532,6 +1534,7 @@ defmodule Calendar.ISO do @doc """ Converts the given datetime into a iodata. + See datetime_to_iodata/12 for more information ## Examples From 3a1a74ebfbaf7e8626427d2b2076229118864629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 31 Dec 2024 08:38:05 +0100 Subject: [PATCH 10/10] Apply suggestions from code review Co-authored-by: Jean Klingler --- lib/elixir/lib/calendar/iso.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 4367efa6861..682f4d3960e 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -1233,7 +1233,7 @@ defmodule Calendar.ISO do @doc """ Converts the given time into a iodata. - See time_to_string/5 for more information + See `time_to_string/5` for more information. ## Examples @@ -1330,7 +1330,7 @@ defmodule Calendar.ISO do @doc """ Converts the given date into a iodata. - See date_to_string/4 for more information + See `date_to_string/4` for more information. ## Examples @@ -1410,7 +1410,7 @@ defmodule Calendar.ISO do @doc """ Converts the given naive_datetime into a iodata. - See naive_datetime_to_iodata/8 for more information + See `naive_datetime_to_iodata/8` for more information. ## Examples @@ -1535,7 +1535,7 @@ defmodule Calendar.ISO do @doc """ Converts the given datetime into a iodata. - See datetime_to_iodata/12 for more information + See `datetime_to_iodata/12` for more information. ## Examples