Skip to content

Commit ab5ed16

Browse files
mccoypiscai-msft
authored andcommitted
[Core] Follow RFC 3339 datetime formatting for AzureJSONEncoder (#20346)
1 parent 36340d9 commit ab5ed16

File tree

3 files changed

+20
-16
lines changed

3 files changed

+20
-16
lines changed

sdk/core/azure-core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Features Added
66

7+
- `azure.core.serialization.AzureJSONEncoder` (introduced in 1.17.0) serializes `datetime.datetime` objects in ISO 8601 format, conforming to RFC 3339's specification. #20190
78
- We now use `azure.core.serialization.AzureJSONEncoder` to serialize `json` input to `azure.core.rest.HttpRequest`.
89

910
### Breaking Changes in the Provisional `azure.core.rest` package

sdk/core/azure-core/azure/core/serialization.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,11 @@ def default(self, o): # pylint: disable=too-many-return-statements
105105
if hasattr(o, "year") and hasattr(o, "hour"):
106106
# astimezone() fails for naive times in Python 2.7, so make make sure o is aware (tzinfo is set)
107107
if not o.tzinfo:
108-
return o.replace(tzinfo=TZ_UTC).isoformat()
109-
return o.astimezone(TZ_UTC).isoformat()
108+
iso_formatted = o.replace(tzinfo=TZ_UTC).isoformat()
109+
else:
110+
iso_formatted = o.astimezone(TZ_UTC).isoformat()
111+
# Replace the trailing "+00:00" UTC offset with "Z" (RFC 3339: https://www.ietf.org/rfc/rfc3339.txt)
112+
return iso_formatted.replace("+00:00", "Z")
110113
# Next try datetime.date or datetime.time
111114
return o.isoformat()
112115
except AttributeError:

sdk/core/azure-core/tests/test_serialization.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def test_dictionary_datetime(json_dumps_with_encoder):
150150
expected = {
151151
"timedelta": "P1DT00H00M00S",
152152
"date": "2021-05-12",
153-
"datetime": '2012-02-24T00:53:52.780000+00:00',
153+
"datetime": '2012-02-24T00:53:52.780000Z',
154154
'time': '11:12:13',
155155
}
156156
assert json.loads(json_dumps_with_encoder(test_obj)) == expected
@@ -167,7 +167,7 @@ def __init__(self):
167167
expected_dict = {
168168
"timedelta": "P1DT00H00M00S",
169169
"date": "2021-05-12",
170-
"datetime": '2012-02-24T00:53:52.780000+00:00',
170+
"datetime": '2012-02-24T00:53:52.780000Z',
171171
'time': '11:12:13',
172172
}
173173
assert json.loads(json_dumps_with_encoder(expected.to_dict())) == expected_dict
@@ -205,10 +205,10 @@ def __init__(self):
205205
expected_dict = {
206206
"_attributes": {
207207
"enabled": True,
208-
"not_before": "2012-02-24T00:53:52.780000+00:00",
209-
"expires": "2032-02-24T00:53:52.780000+00:00",
210-
"created": "2020-02-24T00:53:52.780000+00:00",
211-
"updated": "2021-02-24T00:53:52.780000+00:00",
208+
"not_before": "2012-02-24T00:53:52.780000Z",
209+
"expires": "2032-02-24T00:53:52.780000Z",
210+
"created": "2020-02-24T00:53:52.780000Z",
211+
"updated": "2021-02-24T00:53:52.780000Z",
212212
},
213213
"_id": "id",
214214
"_vault_id": {
@@ -229,39 +229,39 @@ def test_serialize_datetime(json_dumps_with_encoder):
229229
date_obj = datetime.strptime('2015-01-01T00:00:00', "%Y-%m-%dT%H:%M:%S")
230230
date_str = json_dumps_with_encoder(date_obj)
231231

232-
assert date_str == '"2015-01-01T00:00:00+00:00"'
232+
assert date_str == '"2015-01-01T00:00:00Z"'
233233

234234
date_obj = datetime.strptime('1999-12-31T23:59:59', "%Y-%m-%dT%H:%M:%S").replace(tzinfo=NegativeUtcOffset())
235235
date_str = json_dumps_with_encoder(date_obj)
236236

237-
assert date_str == '"2000-01-01T11:59:59+00:00"'
237+
assert date_str == '"2000-01-01T11:59:59Z"'
238238

239239
date_obj = datetime.strptime("2015-06-01T16:10:08.0121", "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=PositiveUtcOffset())
240240
date_str = json_dumps_with_encoder(date_obj)
241241

242-
assert date_str == '"2015-06-01T04:10:08.012100+00:00"'
242+
assert date_str == '"2015-06-01T04:10:08.012100Z"'
243243

244244
date_obj = datetime.min
245245
date_str = json_dumps_with_encoder(date_obj)
246-
assert date_str == '"0001-01-01T00:00:00+00:00"'
246+
assert date_str == '"0001-01-01T00:00:00Z"'
247247

248248
date_obj = datetime.max
249249
date_str = json_dumps_with_encoder(date_obj)
250-
assert date_str == '"9999-12-31T23:59:59.999999+00:00"'
250+
assert date_str == '"9999-12-31T23:59:59.999999Z"'
251251

252252
date_obj = datetime.strptime('2012-02-24T00:53:52.000001Z', "%Y-%m-%dT%H:%M:%S.%fZ")
253253
date_str = json_dumps_with_encoder(date_obj)
254-
assert date_str == '"2012-02-24T00:53:52.000001+00:00"'
254+
assert date_str == '"2012-02-24T00:53:52.000001Z"'
255255

256256
date_obj = datetime.strptime('2012-02-24T00:53:52.780Z', "%Y-%m-%dT%H:%M:%S.%fZ")
257257
date_str = json_dumps_with_encoder(date_obj)
258-
assert date_str == '"2012-02-24T00:53:52.780000+00:00"'
258+
assert date_str == '"2012-02-24T00:53:52.780000Z"'
259259

260260
def test_serialize_datetime_subclass(json_dumps_with_encoder):
261261

262262
date_obj = DatetimeSubclass.strptime('2012-02-24T00:53:52.780Z', "%Y-%m-%dT%H:%M:%S.%fZ")
263263
date_str = json_dumps_with_encoder(date_obj)
264-
assert date_str == '"2012-02-24T00:53:52.780000+00:00"'
264+
assert date_str == '"2012-02-24T00:53:52.780000Z"'
265265

266266
def test_serialize_time(json_dumps_with_encoder):
267267

0 commit comments

Comments
 (0)