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.

7voto

AngelDown Punkte 291

Eigentlich ist es ziemlich einfach. Wenn Sie Daten häufig serialisieren müssen, arbeiten Sie mit ihnen als Zeichenketten. Sie können sie bei Bedarf problemlos wieder in Datumszeitobjekte konvertieren.

Wenn Sie hauptsächlich als Datumszeitobjekte arbeiten müssen, wandeln Sie sie in Zeichenketten um, bevor Sie sie serialisieren.

import json, datetime

date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))

datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))

Wie Sie sehen können, ist die Ausgabe in beiden Fällen gleich. Nur der Typ ist unterschiedlich.

7voto

Peter Graham Punkte 2208

Der einfachste Weg, dies zu tun, besteht darin, den Teil des Diktats, der im Datumsformat vorliegt, in isoformat zu ändern. Dieser Wert wird effektiv ein String in isoformat sein, mit dem json einverstanden ist.

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

6voto

zhigang Punkte 5618

Versuchen Sie dieses mit einem Beispiel zu analysieren:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil

class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)

def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00

if __name__ == '__main__':
    test()

4voto

michal-michalak Punkte 541

Wenn Sie mit Django-Modellen arbeiten, können Sie encoder=DjangoJSONEncoder direkt an den Feldkonstruktor übergeben. Es wird wie ein Charme funktionieren.

from django.core.serializers.json import DjangoJSONEncoder 
from django.db import models 
from django.utils.timezone import now

class Activity(models.Model):
    diff = models.JSONField(null=True, blank=True, encoder=DjangoJSONEncoder)

diff = {
    "a": 1,
    "b": "BB",
    "c": now()
}

Activity.objects.create(diff=diff)

3voto

Mark Punkte 16672

Im Allgemeinen gibt es mehrere Möglichkeiten, Datumszeiten zu serialisieren, wie zum Beispiel:

  1. ISO-String, kurz und kann Zeitzoneinformationen enthalten, z. B. die Antwort von @jgbarah
  2. Zeitstempel (Zeitzoneninformation geht verloren), z. B. die Antwort von @JayTaylor
  3. Wörterbuch der Eigenschaften (einschließlich Zeitzone).

Wenn Sie mit dem letzten Weg einverstanden sind, verarbeitet das Paket json_tricks Daten, Zeiten und Datumszeiten einschließlich Zeitzone.

from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)

was folgendes ergibt:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

Alles, was Sie tun müssen, ist

`pip install json_tricks`

und dann importieren Sie aus json_tricks anstelle von json.

Der Vorteil, es nicht als einzelnen String, Int oder Float zu speichern, liegt darin, dass beim Decodieren: Wenn Sie nur einen String oder insbesondere Int oder Float finden, müssen Sie etwas über die Daten wissen, um zu wissen, ob es sich um eine Datumszeit handelt. Als Wörterbuch können Metadaten gespeichert werden, sodass es automatisch decodiert werden kann, was json_tricks für Sie macht. Es ist auch leicht bearbeitbar für Menschen.

Haftungsausschluss: Es wurde von mir erstellt. Weil ich das gleiche Problem hatte.

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