Skip to content

Commit b53ceff

Browse files
authored
Use iodata for calendar types serialization (#14133)
1 parent bf1a207 commit b53ceff

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

lib/elixir/lib/calendar/duration.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ defmodule Duration do
532532
sign,
533533
Integer.to_string(second),
534534
?.,
535-
ms |> Integer.to_string() |> String.pad_leading(6, "0") |> binary_part(0, p)
535+
Calendar.ISO.microseconds_to_iodata(ms, p)
536536
]
537537
end
538538

lib/elixir/lib/json.ex

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,93 @@ defimpl JSON.Encoder, for: Map do
150150
end
151151
end
152152

153-
defimpl JSON.Encoder, for: [Date, Time, NaiveDateTime, DateTime, Duration] do
153+
defimpl JSON.Encoder, for: Duration do
154154
def encode(value, _encoder) do
155-
[?", @for.to_iso8601(value), ?"]
155+
[?", Duration.to_iso8601(value), ?"]
156+
end
157+
end
158+
159+
defimpl JSON.Encoder, for: Date do
160+
def encode(%{calendar: Calendar.ISO} = date, _encoder) do
161+
%{year: year, month: month, day: day} = date
162+
[?", Calendar.ISO.date_to_iodata(year, month, day), ?"]
163+
end
164+
165+
def encode(value, _encoder) do
166+
[?", Date.to_iso8601(value), ?"]
167+
end
168+
end
169+
170+
defimpl JSON.Encoder, for: Time do
171+
def encode(%{calendar: Calendar.ISO} = time, _encoder) do
172+
%{
173+
hour: hour,
174+
minute: minute,
175+
second: second,
176+
microsecond: microsecond
177+
} = time
178+
179+
[?", Calendar.ISO.time_to_iodata(hour, minute, second, microsecond), ?"]
180+
end
181+
182+
def encode(value, _encoder) do
183+
[?", Time.to_iso8601(value), ?"]
184+
end
185+
end
186+
187+
defimpl JSON.Encoder, for: NaiveDateTime do
188+
def encode(%{calendar: Calendar.ISO} = naive_datetime, _encoder) do
189+
%{
190+
year: year,
191+
month: month,
192+
day: day,
193+
hour: hour,
194+
minute: minute,
195+
second: second,
196+
microsecond: microsecond
197+
} = naive_datetime
198+
199+
[
200+
?",
201+
Calendar.ISO.date_to_iodata(year, month, day),
202+
?T,
203+
Calendar.ISO.time_to_iodata(hour, minute, second, microsecond),
204+
?"
205+
]
206+
end
207+
208+
def encode(value, _encoder) do
209+
[?", NaiveDateTime.to_iso8601(value), ?"]
210+
end
211+
end
212+
213+
defimpl JSON.Encoder, for: DateTime do
214+
def encode(%{calendar: Calendar.ISO} = datetime, _encoder) do
215+
%{
216+
year: year,
217+
month: month,
218+
day: day,
219+
hour: hour,
220+
minute: minute,
221+
second: second,
222+
microsecond: microsecond,
223+
time_zone: time_zone,
224+
utc_offset: utc_offset,
225+
std_offset: std_offset
226+
} = datetime
227+
228+
[
229+
?",
230+
Calendar.ISO.date_to_iodata(year, month, day),
231+
?T,
232+
Calendar.ISO.time_to_iodata(hour, minute, second, microsecond),
233+
Calendar.ISO.offset_to_iodata(utc_offset, std_offset, time_zone, :extended),
234+
?"
235+
]
236+
end
237+
238+
def encode(value, _encoder) do
239+
[?", DateTime.to_iso8601(value), ?"]
156240
end
157241
end
158242

lib/elixir/test/elixir/json_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ defmodule JSONTest do
9999
list = JSON.encode_to_iodata!([1, 1.0, "one", %{1 => 2, 3.0 => 4.0, key: :bar}])
100100
assert is_list(list)
101101
assert IO.iodata_to_binary(list) == "[1,1.0,\"one\",{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}]"
102+
103+
list =
104+
JSON.encode_to_iodata!([
105+
~T[12:34:56.78],
106+
~D[2024-12-31],
107+
~N[2010-04-17 14:00:00.123],
108+
~U[2010-04-17 14:00:00.123Z],
109+
Duration.new!(month: 2, hour: 3)
110+
])
111+
112+
assert IO.iodata_to_binary(list) ==
113+
~s'["12:34:56.78","2024-12-31","2010-04-17T14:00:00.123","2010-04-17T14:00:00.123Z","P2MT3H"]'
102114
end
103115

104116
test "deprecated" do

0 commit comments

Comments
 (0)