2015-06-15 16 views
5

Sto usando python per codificare un OrderedDict con timestamp e ho problemi. I dati che sto cercando di codificare assomiglia a questo:python - using json con OrderedDict e Datetime

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

mi aspetto che questo sia JSON codificato e decodificato per ottenere esattamente gli stessi dati.

Per codificare il timestamp direttamente, senza passare all'ora ISO o Unix, ho utilizzato l'interfaccia json_util di bson come di seguito. Funziona correttamente.

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

Al fine di ottenere un OrderedDict ho usato object_pairs_hook, che funziona anche:

json.loads(x, object_pairs_hook=OrderedDict) 

Tuttavia, se usati insieme, il pasticcio di due cose tra loro e il risultato non è nel formato corretto (Poiché l'interfaccia di bson sta creando un dizionario extra per il timestamp).

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

Questa query finisce per ottenere questo:

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

Il timestamp non viene analizzato correttamente. Qualche suggerimento su come farlo correttamente? (Pickle potrebbe essere una direzione, ma cerco prima altre soluzioni).

+0

Cosa significa '' uscita json_util.object_hook'' per '' datetime'' oggetti? –

+0

@JamesMills output '{"a": {"$ date": 1434383934884}, "b": "b", "c": "c", "d": "d"}'. Questo dizionario extra viene analizzato come OrderDict da object_pairs_hook interrompendo quindi object_hook per decodificarlo. –

+0

Quindi è codificato come UNIX Timestamp come '' {"$ date": ""} ''? –

risposta

2

È possibile definire il proprio decoder che si occuperà sia datetime e OrderedDict e utilizzarlo in object_pairs_hook. Per comodità e test ho anche definito il mio codificatore, ma sei libero di usare quello che hai già.

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

Questo stamperà:

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

Fantastico, grazie. Non ho pensato a questa traccia. –

1

Perché non codificare/decodificare l'oggetto datetime direttamente?

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

Grazie per la risposta. In realtà è un dizionario python molto grande con dizionario annidato e timestamp annidato. Sto cercando di evitare di attraversare manualmente i dati e modificare personalmente il datetime. E poi attraversare di nuovo quando decodifica per cambiare quella indietro. –

+0

Ho pensato che potesse essere così ... – Alexander

+0

Sì, speriamo tutti che la vita sia facile come nell'esempio sopra. :) –