web-dev-qa-db-fra.com

Pourquoi la sérialisation json des objets datetime dans python ne fonctionne pas prête à l'emploi pour les objets datetime

Pourquoi la sérialisation json ne fonctionne-t-elle pas pour les objets datetime. Si je comprends bien la sérialisation json, l'idée de base pour tout objet peut être appelée __str__ fonction intégrée, puis encodez l'URL de l'objet que vous obtenez en réponse. Mais en cas de datetime j'obtiens l'erreur suivante

TypeError: datetime.datetime(2012, 5, 23, 18, 38, 23, 37566) is not JSON serializable

alors qu'il y a un __str__ c'est-à-dire une manière de stringifier l'objet déjà disponible, Mais cela semble être une décision consciente de ne pas le faire, pourquoi en serait-il ainsi?

51
dusual

Non, cela ne fonctionne pas de cette façon dans le module json. Le module vous fournit un encodeur par défaut: json.JSONEncoder. Vous devez l'étendre pour fournir votre implémentation de la méthode default pour sérialiser les objets. Quelque chose comme ça:

import json
import datetime
from time import mktime

class MyEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return int(mktime(obj.timetuple()))

        return json.JSONEncoder.default(self, obj)

print json.dumps(obj, cls=MyEncoder)

Comme d'autres l'ont souligné à juste titre, la raison en est que le standard pour json ne spécifie pas comment la date et l'heure peuvent être représentées.

90
Vikas

Comment aimeriez-vous qu'ils soient sérialisés?

JSON ne spécifie pas comment gérer les dates, donc la bibliothèque python json ne peut pas décider comment les représenter pour vous. Cela dépend complètement de la façon dont l'autre côté (navigateur, script, etc.) gère également les dates en JSON.

10
Martijn Pieters

Un moyen simple de patcher le module json de sorte que la sérialisation prenne en charge datetime.

import json
import datetime

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

Utilisez ensuite la sérialisation json comme vous le faites toujours - cette fois avec datetime étant sérialisé en isoformat.

json.dumps({'created':datetime.datetime.now()})

Résultat: '{"créé": "2015-08-26T14: 21: 31.853855"}'

Voir plus de détails et quelques mises en garde sur: StackOverflow: datetime JSON entre Python et JavaScript

8
davidhadas

Si vous souhaitez obtenir l'encodage et le décodage des heures sans avoir à l'implémenter, vous pouvez utiliser json_tricks , qui est un wrapper qui ajoute l'encodage et le décodage pour divers types populaires. Installez simplement:

pip install json_tricks

puis importez de json_tricks au lieu de json, par exemple:

from json_tricks import dumps, loads
json = dumps({'name': 'MyName', 'birthday': datetime.datetime(1992, 5, 23, 18, 38, 23, 37566)})
me = loads(json)

Avertissement: il est fait par moi. Parce que j'avais le même problème.


Si vous voulez sérialiser automatiquement tout ce qui peut être stratifié, vous pouvez le faire très simplement avec l'implémentation standard:

dumps(obj, default=str)

Mais notez que cela présente des inconvénients, par exemple rien ne sera désérialisé sans effort supplémentaire, et peut-être que parfois vous ne voulez simplement pas sérialiser quelque chose (comme une fonction d'un grand tableau numpy), mais obtenez un avertissement à la place, que cette méthode fera taire.

2
Mark