1266 Stimmen

Wie kann man "datetime.datetime nicht JSON-seriellisierbar" überwinden?

Ich habe ein grundlegendes Wörterbuch wie folgt:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

Wenn ich versuche, jsonify(sample) auszuführen, erhalte ich:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) ist nicht JSON-fähig

Was kann ich tun, damit mein Wörterbuch "sample" den oben genannten Fehler überwinden kann?

Hinweis: Obwohl es möglicherweise nicht relevant ist, werden die Wörterbücher aus dem Abrufen von Datensätzen aus mongodb generiert, bei dem, wenn ich str(sample['somedate']) ausdrucke, die Ausgabe 2012-08-08 21:46:24.862000 ist.

85voto

Jay Taylor Punkte 12391

Für andere, die pymongo für dieses nicht benötigen oder verwenden wollen, können Sie die Konvertierung von datetime JSON leicht mit diesem kleinen Snippet erreichen:

def default(obj):
    """Standard-JSON-Serialisierer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Nicht sicher, wie man %s serialisieren soll' % (obj,))

Verwenden Sie es dann wie folgt:

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

Ausgabe: 

'1365091796124'

68voto

Natim Punkte 16149

Hier ist meine Lösung:

import json

class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return super().default(obj)
        except TypeError:
            return str(obj)

Dann können Sie es so verwenden:

json.dumps(dictionary, cls=DatetimeEncoder)

57voto

Cyker Punkte 8424

Wenn Sie Python3.7 verwenden, ist die beste Lösung die Verwendung von datetime.isoformat() und datetime.fromisoformat(); sie funktionieren sowohl mit naiven als auch mit bewussten datetime-Objekten:

#!/usr/bin/env python3.7

from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json

def default(obj):
    if isinstance(obj, datetime):
        return { '_isoformat': obj.isoformat() }
    raise TypeError('...')

def object_hook(obj):
    _isoformat = obj.get('_isoformat')
    if _isoformat is not None:
        return datetime.fromisoformat(_isoformat)
    return obj

if __name__ == '__main__':
    #d = { 'now': datetime(2000, 1, 1) }
    d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
    s = json.dumps(d, default=default)
    print(s)
    print(d == json.loads(s, object_hook=object_hook))

Ausgabe:

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True

Wenn Sie Python3.6 oder darunter verwenden und nur den Zeitwert interessiert (nicht die Zeitzone), dann können Sie datetime.timestamp() und datetime.fromtimestamp() verwenden;

Wenn Sie Python3.6 oder darunter verwenden und die Zeitzone beachten wollen, dann können Sie diese über datetime.tzinfo erhalten, aber Sie müssen dieses Feld selbst serialisieren; der einfachste Weg, dies zu tun, ist ein weiteres Feld _tzinfo im serialisierten Objekt hinzuzufügen;

Achten Sie abschließend auf die Genauigkeit in all diesen Beispielen;

28voto

Benyamin Jafari Punkte 20585

Sie sollten die Methode .strftime() auf die Methode .datetime.now() anwenden, um sie als eine serialisierbare Methode zu machen.

Hier ist ein Beispiel:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

Ausgabe:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

[UPDATE]:

In Python3.7 und später können Sie einfach die Methode .isoformat() verwenden:

from datetime import datetime

datetime.now().isoformat()

22voto

Saurabh Saha Punkte 812

Die Methode json.dumps kann einen optionalen Parameter namens default akzeptieren, der als Funktion erwartet wird. Jedes Mal, wenn JSON versucht, einen Wert umzuwandeln, von dem es nicht weiß, wie es konvertiert werden soll, wird es die Funktion aufrufen, die wir ihm übergeben haben. Die Funktion erhält das fragliche Objekt und soll die JSON-Repräsentation des Objekts zurückgeben.

def myconverter(o):
 if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter))

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X