Skip to content

Commit ec3424a

Browse files
committed
Fix incorrect padding of microseconds on datetime.datetime
1 parent b524a9a commit ec3424a

2 files changed

Lines changed: 42 additions & 6 deletions

File tree

src/encode.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,14 @@ impl<'p> Serialize for SerializePyObject {
313313
unsafe { pyo3::ffi::PyDateTime_DATE_GET_MICROSECOND(self.ptr) as u32 };
314314
if microsecond != 0 {
315315
dt.push(PERIOD);
316-
dt.extend(itoa::Buffer::new().format(microsecond).bytes());
316+
let mut buf = itoa::Buffer::new();
317+
let formatted = buf.format(microsecond);
318+
let mut to_pad = 6 - formatted.len();
319+
while to_pad != 0 {
320+
dt.push(ZERO);
321+
to_pad -= 1;
322+
}
323+
dt.extend(formatted.bytes());
317324
}
318325
}
319326
if has_tz || self.opts & NAIVE_UTC == NAIVE_UTC {

test/test_datetime.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_datetime_naive(self):
2323
"""
2424
self.assertEqual(
2525
orjson.dumps([datetime.datetime(2000, 1, 1, 2, 3, 4, 123)]),
26-
b'["2000-01-01T02:03:04.123"]',
26+
b'["2000-01-01T02:03:04.000123"]',
2727
)
2828

2929
def test_datetime_naive_utc(self):
@@ -35,7 +35,7 @@ def test_datetime_naive_utc(self):
3535
[datetime.datetime(2000, 1, 1, 2, 3, 4, 123)],
3636
option=orjson.OPT_NAIVE_UTC,
3737
),
38-
b'["2000-01-01T02:03:04.123+00:00"]',
38+
b'["2000-01-01T02:03:04.000123+00:00"]',
3939
)
4040

4141
def test_datetime_min(self):
@@ -342,7 +342,7 @@ def test_datetime_partial_second_pendulum_supported(self):
342342
)
343343
]
344344
),
345-
b'["1937-01-01T12:00:27.87+00:20"]',
345+
b'["1937-01-01T12:00:27.000087+00:20"]',
346346
)
347347

348348
@pytest.mark.skipif(
@@ -392,7 +392,7 @@ def test_datetime_partial_second_pytz(self):
392392
)
393393
]
394394
),
395-
b'["1937-01-01T12:00:27.87+00:20"]',
395+
b'["1937-01-01T12:00:27.000087+00:20"]',
396396
)
397397

398398
def test_datetime_partial_second_dateutil(self):
@@ -409,9 +409,38 @@ def test_datetime_partial_second_dateutil(self):
409409
)
410410
]
411411
),
412-
b'["1937-01-01T12:00:27.87+00:20"]',
412+
b'["1937-01-01T12:00:27.000087+00:20"]',
413413
)
414414

415+
def test_datetime_microsecond_max(self):
416+
"""
417+
datetime.datetime microsecond max
418+
"""
419+
self.assertEqual(
420+
orjson.dumps(datetime.datetime(2000, 1, 1, 0, 0, 0, 999999)),
421+
b'"2000-01-01T00:00:00.999999"',
422+
)
423+
424+
def test_datetime_microsecond_min(self):
425+
"""
426+
datetime.datetime microsecond min
427+
"""
428+
self.assertEqual(
429+
orjson.dumps(datetime.datetime(2000, 1, 1, 0, 0, 0, 1)),
430+
b'"2000-01-01T00:00:00.000001"',
431+
)
432+
433+
@pytest.mark.skipif(pendulum is None, reason="pendulum install broken on win")
434+
def test_datetime_roundtrip(self):
435+
"""
436+
datetime.datetime parsed by pendulum
437+
"""
438+
obj = datetime.datetime(2000, 1, 1, 0, 0, 0, 1, tzinfo=datetime.timezone.utc)
439+
serialized = orjson.dumps(obj).decode("utf-8").replace('"', "")
440+
parsed = pendulum.parse(serialized)
441+
for attr in ("year", "month", "day", "hour", "minute", "second", "microsecond"):
442+
self.assertEqual(getattr(obj, attr), getattr(parsed, attr))
443+
415444

416445
class DateTests(unittest.TestCase):
417446
def test_date(self):

0 commit comments

Comments
 (0)