Python - using json with OrderedDict and Datetime

I am using python to encode OrderedDict with a timestamp, and I'm having problems. The data I'm trying to encode is as follows:

OrderedDict([('a', datetime.datetime(2015, 6, 15, 15, 58, 54, 884000)), ('b', 'b'), ('c', 'c'), ('d', 'd')]) 

I expect this to be encoded and decoded by json to get exactly the same data.

To encode the timestamp directly, without changing the ISO or Unix time, I used the bson json_util interface as shown below. It is working correctly.

 json.dumps(str, default=json_util.default) json.loads(jsonstr, object_hook=json_util.object_hook) 

To get OrderedDict, I used object_pairs_hook, which also works:

 json.loads(x, object_pairs_hook=OrderedDict) 

However, when they are used together, the two things are messy with each other, and the result is not in the correct format (since the bson interface creates an additional dictionary for the timestamp).

 json.loads(jsonstr, object_hook=json_util.object_hook, object_pairs_hook=OrderedDict) 

This request receives the following:

 OrderedDict([(u'a', OrderedDict([(u'$date', 1434383934884L)])), (u'b', u'b'), (u'c', u'c'), (u'd', u'd')]) 

The timestamp is not being processed correctly. Any suggestions on how to do this correctly? (Pickle may be the direction, but first I look for other solutions).

+5
source share
2 answers

You can define your own decoder that will process both datetime and OrderedDict and use it in object_pairs_hook . For convenience and testing, I also defined my own encoder, but you can use the one you already have.

 #!/usr/bin/env python3 import json import datetime from collections import OrderedDict # Test dictionary a = OrderedDict([('a', datetime.datetime(2015, 6, 15, 15, 58, 54, 884000)), ('b', 'b'), ('c', 'c'), ('d', 'd')]) print(a) # Encoder for datetime def encoder(obj): if type(obj) is datetime.datetime: return {'$date$': obj.timestamp()} raise TypeError # Encode s = json.dumps(a, default=encoder) print("JSON:", s) # Decoder for OrderedDict and datetime def decoder(obj): if len(obj) == 1 and len(obj[0]) == 2 and obj[0][0] == '$date$': return datetime.datetime.fromtimestamp(obj[0][1]) else: return OrderedDict(obj) # Decode b = json.loads(s, object_pairs_hook=decoder) print(b) # Compare print("Comparing:", a == b) 

This will print:

 OrderedDict([('a', datetime.datetime(2015, 6, 15, 15, 58, 54, 884000)), ('b', 'b'), ('c', 'c'), ('d', 'd')]) JSON: {"a": {"$date$": 1434409134.884}, "b": "b", "c": "c", "d": "d"} OrderedDict([('a', datetime.datetime(2015, 6, 15, 15, 58, 54, 884000)), ('b', 'b'), ('c', 'c'), ('d', 'd')]) Comparing: True 
+2
source

Why don't you encode / decode a datetime object directly?

 import datetime as dt import json from collections import OrderedDict datetime_encoding = '%Y-%m-%d %H:%M.%S %f' od = OrderedDict([('a', dt.datetime(2015, 6, 15, 15, 58, 54, 884000).strftime(datetime_encoding)), ('b', 'b'), ('c', 'c'), ('d', 'd')]) x = json.dumps(od) od_new = json.loads(x) od_new['a'] = dt.datetime.strptime(od_new['a'], datetime_encoding) >>> od_new {u'a': datetime.datetime(2015, 6, 15, 15, 58, 54, 884000), u'b': u'b', u'c': u'c', u'd': u'd'} 
+1
source

All Articles