python - 使用带有OrderedDict和Datetime的json

时间:2015-06-15 23:20:52

标签: python json

我正在使用python编写带有时间戳的OrderedDict,我遇到了问题。我尝试编码的数据如下所示:

SELECT sum(c.amount) - s.total 
FROM contribution c inner join  (SELECT user_id, sum(solicitude.amount) total
FROM solicitude  GROUP BY c.user_id HAVING user_id = 1 AND status_id = 1  )s
on c.user_id=s.user_id GROUP BY c.user_id,s.total HAVING c.user_id = 1 

我希望这是json编码和解码,以获得完全相同的数据。

为了直接编码时间戳,不改变ISO或Unix时间,我使用了bson的json_util接口,如下所示。它工作正常。

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

为了获得OrderedDict,我使用了object_pairs_hook,它也有效:

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

然而,当一起使用时,两件事情互相混淆,结果的格式不正确(因为bson界面正在为时间戳创建一个额外的字典)。

json.loads(x, object_pairs_hook=OrderedDict)

此查询最终得到:

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

未正确解析时间戳。有关如何正确做到这一点的任何建议? (Pickle可能是一个方向,但我首先寻求其他解决方案。)

2 个答案:

答案 0 :(得分:2)

您可以定义自己的解码器,它将处理datetime和OrderedDict,并在object_pairs_hook中使用它。为了方便和测试,我还定义了自己的编码器,但您可以自由使用已经编码的编码器。

#!/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)

这将打印:

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

答案 1 :(得分:1)

为什么不直接编码/解码日期时间对象?

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'}