diff --git a/lib/elixir/lib/calendar/duration.ex b/lib/elixir/lib/calendar/duration.ex index 8ffeb3ba8d5..b5656ee53d9 100644 --- a/lib/elixir/lib/calendar/duration.ex +++ b/lib/elixir/lib/calendar/duration.ex @@ -532,7 +532,7 @@ defmodule Duration do sign, Integer.to_string(second), ?., - ms |> Integer.to_string() |> String.pad_leading(6, "0") |> binary_part(0, p) + Calendar.ISO.microseconds_to_iodata(ms, p) ] end diff --git a/lib/elixir/lib/json.ex b/lib/elixir/lib/json.ex index b1a38059c17..bedb2b403e1 100644 --- a/lib/elixir/lib/json.ex +++ b/lib/elixir/lib/json.ex @@ -150,9 +150,93 @@ defimpl JSON.Encoder, for: Map do end end -defimpl JSON.Encoder, for: [Date, Time, NaiveDateTime, DateTime, Duration] do +defimpl JSON.Encoder, for: Duration do def encode(value, _encoder) do - [?", @for.to_iso8601(value), ?"] + [?", Duration.to_iso8601(value), ?"] + end +end + +defimpl JSON.Encoder, for: Date do + def encode(%{calendar: Calendar.ISO} = date, _encoder) do + %{year: year, month: month, day: day} = date + [?", Calendar.ISO.date_to_iodata(year, month, day), ?"] + end + + def encode(value, _encoder) do + [?", Date.to_iso8601(value), ?"] + end +end + +defimpl JSON.Encoder, for: Time do + def encode(%{calendar: Calendar.ISO} = time, _encoder) do + %{ + hour: hour, + minute: minute, + second: second, + microsecond: microsecond + } = time + + [?", Calendar.ISO.time_to_iodata(hour, minute, second, microsecond), ?"] + end + + def encode(value, _encoder) do + [?", Time.to_iso8601(value), ?"] + end +end + +defimpl JSON.Encoder, for: NaiveDateTime do + def encode(%{calendar: Calendar.ISO} = naive_datetime, _encoder) do + %{ + year: year, + month: month, + day: day, + hour: hour, + minute: minute, + second: second, + microsecond: microsecond + } = naive_datetime + + [ + ?", + Calendar.ISO.date_to_iodata(year, month, day), + ?T, + Calendar.ISO.time_to_iodata(hour, minute, second, microsecond), + ?" + ] + end + + def encode(value, _encoder) do + [?", NaiveDateTime.to_iso8601(value), ?"] + end +end + +defimpl JSON.Encoder, for: DateTime do + def encode(%{calendar: Calendar.ISO} = datetime, _encoder) do + %{ + year: year, + month: month, + day: day, + hour: hour, + minute: minute, + second: second, + microsecond: microsecond, + time_zone: time_zone, + utc_offset: utc_offset, + std_offset: std_offset + } = datetime + + [ + ?", + Calendar.ISO.date_to_iodata(year, month, day), + ?T, + Calendar.ISO.time_to_iodata(hour, minute, second, microsecond), + Calendar.ISO.offset_to_iodata(utc_offset, std_offset, time_zone, :extended), + ?" + ] + end + + def encode(value, _encoder) do + [?", DateTime.to_iso8601(value), ?"] end end diff --git a/lib/elixir/test/elixir/json_test.exs b/lib/elixir/test/elixir/json_test.exs index 4d8b97d7449..2955add88cc 100644 --- a/lib/elixir/test/elixir/json_test.exs +++ b/lib/elixir/test/elixir/json_test.exs @@ -99,6 +99,18 @@ defmodule JSONTest do list = JSON.encode_to_iodata!([1, 1.0, "one", %{1 => 2, 3.0 => 4.0, key: :bar}]) assert is_list(list) assert IO.iodata_to_binary(list) == "[1,1.0,\"one\",{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}]" + + list = + JSON.encode_to_iodata!([ + ~T[12:34:56.78], + ~D[2024-12-31], + ~N[2010-04-17 14:00:00.123], + ~U[2010-04-17 14:00:00.123Z], + Duration.new!(month: 2, hour: 3) + ]) + + assert IO.iodata_to_binary(list) == + ~s'["12:34:56.78","2024-12-31","2010-04-17T14:00:00.123","2010-04-17T14:00:00.123Z","P2MT3H"]' end test "deprecated" do