412 votes

JSON datetime entre Python et JavaScript

Je veux envoyer un objet datetime.datetime sous forme sérialisée depuis Python en utilisant JSON et désérialiser en JavaScript en utilisant JSON. Quelle est la meilleure façon de procéder ?

377voto

JT. Points 300

Vous pouvez ajouter le paramètre "default" à json.dumps pour gérer cela :

>>> dthandler = lambda obj: (
...     obj.isoformat()
...     if isinstance(obj, datetime.datetime)
...     or isinstance(obj, datetime.date)
...     else None)
>>> json.dumps(datetime.datetime.now(), default=dthandler)
'"2010-04-20T20:08:21.634121"'

Ce qui est ISO 8601 format.

Une fonction de traitement par défaut plus complète :

def handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    elif isinstance(obj, ...):
        return ...
    else:
        raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj))

Mise à jour : Ajout de la sortie du type ainsi que de la valeur.
Mise à jour : date de la poignée également

88voto

mdorseif Points 7473

Pour les projets inter-langues, j'ai découvert que les chaînes contenant des RfC 3339 Les dates sont le meilleur moyen d'y parvenir. Une date RfC 3339 ressemble à ceci :

  1985-04-12T23:20:50.52Z

Je pense que la plupart du format est évident. La seule chose un peu inhabituelle est peut-être le "Z" à la fin. Il signifie GMT/UTC. Vous pouvez également ajouter un décalage de fuseau horaire comme +02:00 pour CEST (Allemagne en été). Personnellement, je préfère garder tout en UTC jusqu'à l'affichage.

Pour l'affichage, les comparaisons et le stockage, vous pouvez laisser le format chaîne dans toutes les langues. Si vous avez besoin de la date pour des calculs, il est facile de la reconvertir en un objet date natif dans la plupart des langues.

Donc, générez le JSON comme ceci :

  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%S'))

Malheureusement, le constructeur de date des Javascripts n'accepte pas les chaînes de la RfC 3339, mais il existe de nombreuses autres possibilités. Analyseurs syntaxiques disponible sur l'Internet.

huTools.hujson tente de gérer les problèmes d'encodage les plus courants que vous pouvez rencontrer dans le code Python, y compris les objets date/datetime, tout en gérant correctement les fuseaux horaires.

71voto

user240515 Points 1282

J'ai trouvé une solution.

Disons que vous avez un objet Python de type datetime, d créé avec datetime.now(). Sa valeur est :

datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)

Vous pouvez le sérialiser en JSON comme une chaîne de date ISO 8601 :

import json    
json.dumps(d.isoformat())

L'objet datetime de l'exemple serait sérialisé comme :

'"2011-05-25T13:34:05.787000"'

Cette valeur, une fois reçue dans la couche Javascript, peut construire un objet Date :

var d = new Date("2011-05-25T13:34:05.787000");

Depuis la version 1.8.5 de Javascript, les objets Date disposent d'une méthode toJSON, qui renvoie une chaîne dans un format standard. Pour sérialiser l'objet Javascript ci-dessus en JSON, la commande serait donc la suivante :

d.toJSON()

Ce qui vous donnerait :

'2011-05-25T20:34:05.787Z'

Cette chaîne, une fois reçue en Python, pourrait être désérialisée en un objet datetime :

datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')

Cela donne l'objet datetime suivant, qui est le même que celui avec lequel vous avez commencé et qui est donc correct :

datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)

52voto

ramen Points 489

Utilisation de json Si vous êtes un utilisateur de JSONEncoder, vous pouvez sous-classer JSONEncoder et surcharger la méthode default() pour fournir vos propres sérialiseurs personnalisés :

import json
import datetime

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

Ensuite, vous pouvez l'appeler comme ceci :

>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'

31voto

Chris Arndt Points 630

Voici une solution assez complète pour encoder et décoder récursivement les objets datetime.datetime et datetime.date en utilisant la bibliothèque standard json module. Cela nécessite Python >= 2.6 car le module %f dans la chaîne de format de datetime.datetime.strptime() n'est supporté que depuis. Pour la prise en charge de Python 2.5, abandonnez la fonction %f et retirer les microsecondes de la chaîne de date ISO avant d'essayer de la convertir, mais vous perdrez la précision des microsecondes, bien sûr. Pour l'interopérabilité avec les chaînes de date ISO provenant d'autres sources, qui peuvent inclure un nom de fuseau horaire ou un décalage UTC, vous devrez peut-être aussi retirer certaines parties de la chaîne de date avant la conversion. Pour un analyseur complet des chaînes de date ISO (et de nombreux autres formats de date), consultez le logiciel tiers dateutil module.

Le décodage ne fonctionne que lorsque les chaînes de dates ISO sont des valeurs dans une notation JavaScript ou dans des structures imbriquées à l'intérieur d'un objet. Les chaînes de date ISO qui sont des éléments d'un tableau de niveau supérieur seront pas être décodé.

C'est-à-dire que ça marche :

date = datetime.datetime.now()
>>> json = dumps(dict(foo='bar', innerdict=dict(date=date)))
>>> json
'{"innerdict": {"date": "2010-07-15T13:16:38.365579"}, "foo": "bar"}'
>>> loads(json)
{u'innerdict': {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)},
u'foo': u'bar'}

Et ça aussi :

>>> json = dumps(['foo', 'bar', dict(date=date)])
>>> json
'["foo", "bar", {"date": "2010-07-15T13:16:38.365579"}]'
>>> loads(json)
[u'foo', u'bar', {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)}]

Mais cela ne fonctionne pas comme prévu :

>>> json = dumps(['foo', 'bar', date])
>>> json
'["foo", "bar", "2010-07-15T13:16:38.365579"]'
>>> loads(json)
[u'foo', u'bar', u'2010-07-15T13:16:38.365579']

Voici le code :

__all__ = ['dumps', 'loads']

import datetime

try:
    import json
except ImportError:
    import simplejson as json

class JSONDateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime)):
            return obj.isoformat()
        else:
            return json.JSONEncoder.default(self, obj)

def datetime_decoder(d):
    if isinstance(d, list):
        pairs = enumerate(d)
    elif isinstance(d, dict):
        pairs = d.items()
    result = []
    for k,v in pairs:
        if isinstance(v, basestring):
            try:
                # The %f format code is only supported in Python >= 2.6.
                # For Python <= 2.5 strip off microseconds
                # v = datetime.datetime.strptime(v.rsplit('.', 1)[0],
                #     '%Y-%m-%dT%H:%M:%S')
                v = datetime.datetime.strptime(v, '%Y-%m-%dT%H:%M:%S.%f')
            except ValueError:
                try:
                    v = datetime.datetime.strptime(v, '%Y-%m-%d').date()
                except ValueError:
                    pass
        elif isinstance(v, (dict, list)):
            v = datetime_decoder(v)
        result.append((k, v))
    if isinstance(d, list):
        return [x[1] for x in result]
    elif isinstance(d, dict):
        return dict(result)

def dumps(obj):
    return json.dumps(obj, cls=JSONDateTimeEncoder)

def loads(obj):
    return json.loads(obj, object_hook=datetime_decoder)

if __name__ == '__main__':
    mytimestamp = datetime.datetime.utcnow()
    mydate = datetime.date.today()
    data = dict(
        foo = 42,
        bar = [mytimestamp, mydate],
        date = mydate,
        timestamp = mytimestamp,
        struct = dict(
            date2 = mydate,
            timestamp2 = mytimestamp
        )
    )

    print repr(data)
    jsonstring = dumps(data)
    print jsonstring
    print repr(loads(jsonstring))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X