Odd behaviour of DjangoJSONSerializer when serializing datetimes with/without microseconds

139 views
Skip to first unread message

Robert Kirberich

unread,
Mar 10, 2016, 7:52:49 AM3/10/16
to Django users
Hi,

I stumbled across this yesterday while trying to figure out why some of my tests would sometimes fail when serializing and deserializing datetimes to JSON.

DjangoJSONSerializer only includes the milliseconds in the encoded string if the original datetime has a non-zero microsecond value - this is fine when only dealing with the JSON in Javascript, but in python it requires two different cases when decoding.

To make things even more confusing, the milliseconds field can be included even if it's zero:

import datetime
from django.core.serializers.json import DjangoJSONEncoder
e
= DjangoJSONEncoder()

e
.default(datetime.datetime(year=2016, month=1, day=1, hour=1, minute=1, second=1, microsecond=1))
'2016-01-01T01:01:01.000'

e
.default(datetime.datetime(year=2016, month=1, day=1, hour=1, minute=1, second=1, microsecond=0))
'2016-01-01T01:01:01'



This seems like a bug to me (easily fixed by always including the milliseconds), but I wanted to check first if there's a reason for this behaviour, as that code has been there for ages. If this is a bug, I'll be happy to send a PR.


Cheers
Rob

Simon Charette

unread,
Mar 10, 2016, 12:12:25 PM3/10/16
to Django users
Hi Rob,

The fact DjangoJSONEncoder strips microseconds is definitely a bug that should
be reported:

> e.default(datetime.datetime(year=2016, month=1, day=1, hour=1, minute=1, second=1, microsecond=123456))
> '2016-01-01T01:01:01.123'

I think always including the microseconds could make sense but I'm not sure it's
worth it in regard to backward incompatiblity. Keep in mind that Django relies
on the `datetime.datetime.isoformat` stdlib method which does the stripping
internally:

> datetime.datetime(year=2016, month=1, day=1, hour=1, minute=1, second=1).isoformat()
> '2016-01-01T01:01:01'

Cheers,
Simon

> e.default(datetime.datetime(year=2016, month=1, day=1, hour=1, minute=1, second=1, microsecond=123456))
> '2016-01-01T01:01:01.123'

I think always including the microseconds could make sense but since it might have backward compatibility

Simon Charette

unread,
Mar 10, 2016, 12:20:58 PM3/10/16
to Django users
It looks like I talked to fast.

The microseconds are explicitly stripped because the string format used is based on ECMA-262:

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15

From what I understand JavaScript dates are limited to millisecond precision.

Simon
Reply all
Reply to author
Forward
0 new messages