2015-06-15 7 views
5

Ich benutze Python, um ein OrderedDict mit Zeitstempel darin zu kodieren, und ich habe Probleme. Die Daten, die ich zu kodieren versuche sieht wie folgt aus:Python - Verwenden von Json mit OrderedDict und Datetime

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

ich dies erwarten json und genau die gleichen Daten erhalten decodiert codiert werden.

Um Timestamp direkt zu codieren, ohne auf ISO oder Unix-Zeit zu ändern, habe ich BSONs json_util-Schnittstelle wie folgt verwendet. Es funktioniert korrekt.

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

Um eine OrderedDict zu bekommen habe ich object_pairs_hook, die auch funktioniert:

json.loads(x, object_pairs_hook=OrderedDict) 

Wenn jedoch zusammen verwendet werden, die zwei Dinge Chaos miteinander, und das Ergebnis ist nicht im richtigen Format (Da die bson-Schnittstelle ein zusätzliches Wörterbuch für den Zeitstempel erstellt).

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

Diese Abfrage landet diese bekommen:

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

Der Zeitstempel nicht korrekt analysiert wird, aus. Irgendwelche Vorschläge, wie man das richtig macht? (Pickle kann eine Richtung sein, aber ich suche zuerst andere Lösungen).

+0

Was '' tut json_util.object_hook'' Ausgang für '' datetime'' Objekte? –

+0

@JamesMills Ausgabe '{"a": {"$ date": 1434383934884}, "b": "b", "c": "c", "d": "d"}. Dieses zusätzliche Wörterbuch wird als OrderDict von object_pairs_hook analysiert und stoppt damit object_hook, um es zu dekodieren. –

+0

So ist es als UNIX-Timestamp als "{" $ date ":" ""} "'? –

Antwort

2

Sie können Ihren eigenen Decoder definieren, die sowohl Datetime und OrderedDict behandelt und es in object_pairs_hook verwenden. Für den Komfort und das Testen habe ich auch meinen eigenen Encoder definiert, aber Sie können den bereits vorhandenen verwenden.

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

Dies drucken:

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 
+0

Super, danke. Ich habe nicht über diese Strecke nachgedacht. –

1

Warum codieren/dekodieren Sie das Datetime-Objekt nicht direkt?

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

Danke für die Antwort. In Wirklichkeit ist es ein sehr großes Python-Wörterbuch mit verschachteltem Wörterbuch und verschachteltem Zeitstempel. Ich versuche zu vermeiden, manuell die Daten zu durchlaufen und die Datetime selbst zu ändern. Und dann noch einmal beim Dekodieren durchqueren, um das zurück zu ändern. –

+0

Ich dachte, das könnte der Fall sein ... – Alexander

+0

Ja, wir alle hoffen, das Leben ist so einfach wie im obigen Beispiel. :) –