2012-05-23 15 views
50

? Por qué la serialización json no funciona para objetos datetime. Como entiendo la serialización json, la idea básica para cualquier objeto puede ser llamar a la función integrada __str__ y luego urlencode el objeto que obtienes como respuesta. Pero en el caso de fecha y hora me sale el siguiente error¿Por qué la serialización json de objetos datetime en python no funciona de la caja para objetos datetime

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

mientras que hay una __str__ es decir, una forma de stringifying el objeto ya está disponible, pero parece que la decisión consciente de no hacerlo, ¿por qué habría que ser el caso ?

+8

Estás entendiendo mal cómo funciona json. No tiene nada que ver con el método __str__. JSON no tiene un tipo de fecha y hora, por lo que es imposible codificar sin pérdida de tiempo una fecha en JSON, sin algún tipo de lógica especial en el extremo receptor. Por lo tanto, la biblioteca (lógicamente) hace que lo hagas tú mismo convirtiendo a una marca de tiempo Unix o cadena de fecha ISO o algo así y haciendo explícito que la conversión es necesaria. –

+3

@TylerEaves Esto es cualquier cosa menos lógico. Es posible codificar sin pérdida de tiempo una fecha a una cadena o int, y muchos casos de uso que requieren convertir de dict, a json, a dict nuevamente sin abandonar el ecosistema de python, sin embargo, el módulo json no puede manejar este caso sin una costumbre manejador de fecha y hora ¡¿De Verdad?! Al ver la gran cantidad de preguntas sobre el tema, me gustaría decir que no estoy solo en mi incredulidad. –

Respuesta

88

No, no funciona de esa manera en el módulo json. El módulo le proporciona un codificador predeterminado: json.JSONEncoder. Debe extender esto para proporcionar su implementación del método default para serializar objetos. Algo como esto:

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) 

Como otros señalaron correctamente, la razón es que el standard for json no especifica la forma de fecha y hora puede ser representado.

+3

Excelente respuesta. Gracias –

+4

cómo decodificar esta fecha y hora en el frente? Estoy preguntando sobre la decodificación de este decimal. – Clayton

+1

@Clayton, lo que obtendrás en la respuesta JSON es la marca de tiempo de Unix. [Esta pregunta] (http://stackoverflow.com/questions/847185/convert-a-unix-timestamp-to-time-in-javascript) responde cómo convertir la marca de tiempo de Unix hasta la fecha. – Vikas

10

¿Cómo le gustaría que se serializaran?

JSON no especifica cómo manejar las fechas, por lo que la biblioteca python json no puede tomar una decisión sobre cómo representarlas. Eso depende completamente de cómo el otro lado (navegador, script, lo que sea) maneja las fechas en JSON también.

+2

Con una serialización predeterminada, no necesariamente le importa. Solo necesita poder ingresar al formato json y retroceder sin demasiados problemas. Ciertamente, la falla en la fecha y hora es la respuesta incorrecta. –

+0

@JoshuaKolden: pero en un * formato de intercambio *, debe preocuparse. ¿Cómo quiere la biblioteca JSON en Java o en una aplicación de JavaScript la fecha? –

+1

Entonces es cuando uno tendría que personalizar. De manera predeterminada, si voy de python a json a python, no funcionar de manera predeterminada en los tipos de datos comunes solo agrega una sobrecarga innecesaria. Además, esos otros idiomas también tienen conversiones estándar para json, por lo que uno podría simplemente comenzar con eso como un buen valor predeterminado. –

8

Una manera simple de parchear el módulo json de modo que la serialización sea compatible con datetime.

import json 
import datetime 

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

que utiliza la serialización json como siempre lo hace - esta vez con datetime ser serializado como isoformat.

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

El resultado es: '{ "creado": "2015-08-26T14: 21: 31.853855"}'

Ver más detalles y algunas palabras de precaución en: StackOverflow: JSON datetime between Python and JavaScript

+0

La mejor solución que he visto. Parche de una línea –

2

Si Si desea obtener la codificación y la decodificación de las fechas, sin tener que implementarlas, puede usar json_tricks, que es un contenedor que agrega codificación y decodificación para varios tipos populares. Sólo tiene que instalar:

pip install json_tricks 

y luego importar de json_tricks en lugar de json, por ejemplo .:

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

responsabilidad: está hecho por mí. Porque tuve el mismo problema.


Si desea realizar una serie automáticamente cualquier cosa que pueda ser Stringified, se puede hacer eso con sólo la implementación estándar muy fácilmente:

dumps(obj, default=str) 

Pero tenga en cuenta que esto tiene desventajas, por ejemplo nada de esto se deserializará sin un esfuerzo extra, y tal vez a veces simplemente no desee serializar algo (como una función de una matriz numpy grande), sino que reciba una advertencia, que este método silenciará.

+0

Agradable por mencionar default = str. La solución más fácil para la mayoría de las situaciones comunes. – JJC

Cuestiones relacionadas