¿Cómo superar "datetime.datetime not JSON serializable"?
Frecuentes
Visto 845,828 equipos
1113
Tengo un dict básico de la siguiente manera:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Cuando trato de hacer jsonify(sample)
Yo obtengo:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
¿Qué puedo hacer para que la muestra de mi diccionario supere el error anterior?
Nota: Aunque puede no ser relevante, los diccionarios se generan a partir de la recuperación de registros de mongodb
donde cuando imprimo str(sample['somedate'])
, la salida es 2012-08-08 21:46:24.862000
.
30 Respuestas
1205
Mi vertedero JSON rápido y sucio que come fechas y todo:
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
default
es una función aplicada a objetos que no son serializables.
En este caso esstr
, por lo que simplemente convierte todo lo que no sabe en cadenas. Lo cual es excelente para la serialización, pero no tanto cuando se deserializa (de ahí el "rápido y sucio"), ya que cualquier cosa podría haber sido encadenada sin previo aviso, por ejemplo, una función o una matriz numpy.
Respondido el 27 de Septiembre de 21 a las 09:09
Esto es increíble, pero desafortunadamente no entendí lo que sucedió. ¿Alguien puede explicar esta respuesta? - Kishor Pawar
@KishorPawar: default
es una función aplicada a objetos que no son serializables. en este caso es str
, por lo que simplemente convierte todo lo que no sabe en cadenas. Lo cual es excelente para la serialización, pero no tanto cuando se deserializa (de ahí el "rápido y sucio"), ya que cualquier cosa podría haber sido encadenada sin previo aviso, por ejemplo, una función o una matriz numpy. - Marcos
@Mark increíble. Gracias. Útil cuando conoce el tipo de esos valores no serializables como fechas. - Kishor Pawar
@jjmontes, no sirve para todo, por ejemplo json.dumps({():1,type(None):2},default=str)
plantea TypeError
, no puede tener tipo o tupla. - Alancalvitti
Lo siento despues de este comentario solo encontre que es un error de sintaxis y no de default=str
. Gracias por esto - Santhosh
500
Actualizado para 2018
La respuesta original acomodó la forma en que los campos de "fecha" de MongoDB se representaron como:
{"$date": 1506816000000}
Si desea una solución genérica de Python para serializar datetime
a json, echa un vistazo La respuesta de @jjmontes para una solución rápida que no requiere dependencias.
Como está utilizando mongoengine (según los comentarios) y pymongo es una dependencia, pymongo tiene utilidades integradas para ayudar con la serialización json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Ejemplo de uso (serialización):
from bson import json_util
import json
json.dumps(anObject, default=json_util.default)
Ejemplo de uso (deserialización):
json.loads(aJsonString, object_hook=json_util.object_hook)
Django
Django proporciona un nativo DjangoJSONEncoder
serializador que se ocupa de este tipo de manera adecuada.
Ver https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder
from django.core.serializers.json import DjangoJSONEncoder
return json.dumps(
item,
sort_keys=True,
indent=1,
cls=DjangoJSONEncoder
)
Una diferencia que he notado entre DjangoJSONEncoder
y usando una costumbre default
Me gusta esto:
import datetime
import json
def default(o):
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()
return json.dumps(
item,
sort_keys=True,
indent=1,
default=default
)
Es que Django despoja un poco de los datos:
"last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder
"last_login": "2018-08-03T10:51:42.990239", # default
Por lo tanto, es posible que deba tener cuidado con eso en algunos casos.
Respondido el 11 de diciembre de 18 a las 20:12
¿Es una buena/mala práctica mezclar varias bibliotecas, es decir, tener mongoengine para insertar documentos y pymongo para consulta/recuperación? - Rolando
No es una mala práctica, solo implica cierta dependencia de las bibliotecas que usa su biblioteca principal. Si no puede lograr lo que necesita de mongoengine, baje a pymongo. Es lo mismo con Django MongoDB
. Con el último, intentaría permanecer dentro del ORM de django para mantener un estado agnóstico de back-end. Pero a veces no puede hacer lo que necesita en la abstracción, por lo que despliega una capa. En este caso, no tiene ninguna relación con su problema, ya que solo está utilizando métodos de utilidad para acompañar el formato JSON. - jdi
Estoy probando esto con Flask y parece que al usar json.dump, no puedo poner un envoltorio jsonify() a su alrededor para que regrese en application/json. Intentando devolver jsonify(json.dumps(sample, default=json_util.default)) - Rolando
@amit No se trata tanto de memorizar la sintaxis, sino de aprender a leer documentación y almacenar suficiente información en mi cabeza para reconocer dónde y cuándo necesito recuperarla nuevamente. En este caso, uno podría decir "Oh, un objeto personalizado con json" y luego actualizar rápidamente ese uso: jdi
@guyskk No he rastreado cambios en bjson o mongo desde que escribí esto hace 5 años. Pero si desea controlar la serialización de la fecha y hora, debe escribir su propia función de controlador predeterminada como se ilustra en la respuesta dada por jgbarah: jdi
526
Sobre la base de otras respuestas, una solución simple basada en un serializador específico que simplemente convierte datetime.datetime
y datetime.date
objetos a cadenas.
from datetime import date, datetime
def json_serial(obj):
"""JSON serializer for objects not serializable by default json code"""
if isinstance(obj, (datetime, date)):
return obj.isoformat()
raise TypeError ("Type %s not serializable" % type(obj))
Como se ve, el código solo verifica si el objeto es de clase datetime.datetime
or datetime.date
, y luego usa .isoformat()
para producir una versión serializada del mismo, de acuerdo con el formato ISO 8601, AAAA-MM-DDTHH:MM:SS (que se decodifica fácilmente con JavaScript). Si se buscan representaciones serializadas más complejas, se podría usar otro código en lugar de str() (ver otras respuestas a esta pregunta para ver ejemplos). El código termina lanzando una excepción, para tratar el caso de que se llame con un tipo no serializable.
Esta función json_serial se puede utilizar de la siguiente manera:
from datetime import datetime
from json import dumps
print dumps(datetime.now(), default=json_serial)
Los detalles sobre cómo funciona el parámetro predeterminado para json.dumps se pueden encontrar en Sección Uso básico de la documentación del módulo json.
respondido 09 mar '18, 00:03
sí, la respuesta correcta, más bonita import datetime y if isinstance(obj, datetime.datetime), perdí mucho tiempo porque no usé from datetime import datetime , de todos modos gracias - Sergio
pero esto no explica cómo deserializarlo con el tipo correcto, ¿no? - Trin Azul
No, @BlueTrin, no se dijo nada al respecto. En mi caso, estoy deserializando en JavaScript, que funciona de forma inmediata. - jgbarah
Esto provocará un comportamiento inesperado si el módulo json alguna vez se actualiza para incluir la serialización de objetos de fecha y hora. - Justin
@serg Pero convertir los tiempos a UTC unificaría 01:00:00+01:00
y 02:00:00+00:00
que se supone que no son lo mismo, dependiendo del contexto. Por supuesto, se refieren al mismo punto en el tiempo, pero la compensación podría ser un aspecto relevante del valor. - Alfa
252
Acabo de encontrar este problema y mi solución es subclase json.JSONEncoder
:
from datetime import datetime
import json
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
return json.JSONEncoder.default(self, o)
En su llamada, haga algo como: json.dumps(yourobj, cls=DateTimeEncoder)
La .isoformat()
Obtuve de una de las respuestas anteriores.
respondido 21 nov., 14:09
actualizado porque implementar un JSONEncoder personalizado debería ser la forma correcta de hacerlo: 3k-
Esta no solo debería ser la respuesta principal, sino que debería ser parte del codificador json normal. Si tan solo la decodificación fuera menos ambigua... - Joost
Para aquellos que usan Django, vea DjangoJSONEncoder
. docs.djangoproject.com/en/dev/topics/serialization/… - s kirby
Súper útil. La última línea podría ser return super(DateTimeEncoder, self).default(o)
- bob stein
Con Python 3, la última línea es aún más simple: return super().default(o)
- ariddell
42
si está usando python3.7, entonces la mejor solución es usar
datetime.isoformat()
y
datetime.fromisoformat()
; trabajan con ingenuos y conscientes datetime
objetos:
#!/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))
salida:
{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True
si está utilizando python3.6 o inferior, y solo le importa el valor del tiempo (no la zona horaria), entonces puede usar datetime.timestamp()
y
datetime.fromtimestamp()
en lugar de;
si está utilizando python3.6 o inferior, y le importa la zona horaria, puede obtenerlo a través de datetime.tzinfo
, pero debe serializar este campo usted mismo; la forma más fácil de hacer esto es agregar otro campo _tzinfo
en el objeto serializado;
finalmente, tenga cuidado con las precisiones en todos estos ejemplos;
Respondido 28 Jul 21, 19:07
datetime.isoformat() también está presente en Python 2.7: docs.python.org/2/library/… - powlo
Solución muy útil. ¿Podría también apoyar datetime.time
? - idbrii
@idbrii Como dijo @egvo, te olvidaste default=default
en su edición, que introdujo el error. Pero tienes razón super().default(obj)
es inútil aquí. De hecho, provino de un ejemplo de json-encoder donde es útil. - Cyker
65
Aquí está mi solución:
import json
class DatetimeEncoder(json.JSONEncoder):
def default(self, obj):
try:
return super().default(obj)
except TypeError:
return str(obj)
Entonces puedes usarlo así:
json.dumps(dictionnary, cls=DatetimeEncoder)
Respondido el 01 de Septiembre de 20 a las 13:09
aceptar. Mucho mejor, al menos fuera del contexto mongodb. Tu puedes hacer isinstance(obj, datetime.datetime)
dentro del TypeError, agregue más tipos para manejar y termine con el str(obj)
or repr(obj)
. Y todos sus volcados pueden apuntar a esta clase especializada. - JL Peyret
@Natim esta solución es la mejor. +1 - Rayo Souvik
¿Qué pasa con la decodificación? - Tomás Sauvajón
@ThomasSauvajon stackoverflow.com/a/40489783/186202 - natim
140
Convertir la fecha en una cadena
sample['somedate'] = str( datetime.utcnow() )
Respondido 08 Abr '18, 14:04
¿Y cómo podría deserializarlo en Python? - wobmene
El problema es si tiene muchos objetos de fecha y hora incrustados profundamente en una estructura de datos, o si son aleatorios. Este no es un método confiable. - rebotes
para deserializar: oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Formatos obtenidos de: docs.python.org/2/library/datetime.html - novela
Votado negativo porque ignora la información de la zona horaria. Manten eso en mente .now()
utiliza la hora local, sin indicarlo. Al menos .utcnow()
debe usarse (y luego agregar +0000 o Z) - Daniel F
@DanielF At least .utcnow() should be used
No exactamente, datetime.now(timezone.utc)
se recomienda, consulte la advertencia en: docs.python.org/3.8/library/…. - Toreno96
20
Deberías aplicar .strftime()
método en .datetime.now()
método para hacerlo como un serializable método.
He aquí un ejemplo:
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
Salida:
Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}
Respondido el 20 de junio de 21 a las 08:06
22
El método json.dumps puede aceptar un parámetro opcional llamado predeterminado que se espera que sea una función. Cada vez que JSON intenta convertir un valor, no sabe cómo convertirlo, llamará a la función que le pasamos. La función recibirá el objeto en cuestión y se espera que devuelva la representación JSON del objeto.
def myconverter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
print(json.dumps(d, default = myconverter))
Respondido 31 Jul 18, 22:07
84
Para otros que no necesitan o no quieren usar la biblioteca pymongo para esto... pueden lograr la conversión JSON de fecha y hora fácilmente con este pequeño fragmento:
def default(obj):
"""Default JSON serializer."""
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('Not sure how to serialize %s' % (obj,))
Entonces úsalo así:
import datetime, json
print json.dumps(datetime.datetime.now(), default=default)
salida:
'1365091796124'
Respondido el 05 de enero de 16 a las 13:01
No deberia millis=
tener sangría dentro de la instrucción if? Probablemente también sea mejor usar str(obj) para obtener el formato ISO, que creo que es más común. - rebotes
¿Por qué quieres que esté sangrado? Este fragmento funciona y la salida resultante se puede deserializar/analizar fácilmente desde javascript. - Jay Taylor
Porque obj puede no ser un objeto [hora, fecha, fecha y hora] - rebotes
su ejemplo es incorrecto si la zona horaria local tiene un desplazamiento UTC distinto de cero (la mayoría de ellos). datetime.now()
devuelve la hora local (como un objeto ingenuo de fecha y hora) pero su código asume que obj
está en UTC si no reconoce la zona horaria. Usar datetime.utcnow()
en lugar de. - jfs
Se ajustó para generar un error de tipo si obj no se reconoce según la recomendación de la documentación de Python en docs.python.org/2/library/json.html#basic-usage. - Jay Taylor
21
Mi solución (con menos verbosidad, creo):
def default(o):
if type(o) is datetime.date or type(o) is datetime.datetime:
return o.isoformat()
def jsondumps(o):
return json.dumps(o, default=default)
Entonces usa jsondumps
en lugar de json.dumps
. Se imprimirá:
>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'
Si lo desea, luego puede agregar otros casos especiales a este con un simple giro del default
método. Ejemplo:
def default(o):
if type(o) is datetime.date or type(o) is datetime.datetime:
return o.isoformat()
if type(o) is decimal.Decimal:
return float(o)
Respondido 31 Jul 13, 01:07
Debe usar isinstance(o, (datetime.date, datetime.datetime,)). Probablemente no estaría de más incluir datetime.time también. - rebotes
Ya no creo que sea una buena solución. Probablemente las conversiones deberían ocupar un lugar más privilegiado, y también un lugar más comprensible, en su código, para que sepa a qué se está convirtiendo cuando coloca cosas en una base de datos, o lo que sea, en lugar de tener todo hecho por un función transparente. Pero no sé. - fiatjaf
JSON es bueno para serializar datos para su procesamiento posterior. Es posible que no sepa exactamente cuáles son esos datos. Y no deberías necesitarlo. La serialización de JSON debería funcionar. Al igual que convertir unicode a ascii debería. La incapacidad de Python para hacer esto sin funciones oscuras hace que su uso sea molesto. La validación de la base de datos es un tema aparte en mi opinión. - rebotes
No, no debería "simplemente funcionar". Si no sabe cómo ocurrió la serialización y tiene que acceder a los datos más tarde desde otro programa/lenguaje, entonces está perdido. - fiatjaf
JSON se usa comúnmente para cadenas, enteros, flotantes, fechas (estoy seguro de que otros también usan moneda, temperaturas, comúnmente). Pero datetime es parte de la biblioteca estándar y debería admitir la deserialización. Si no fuera por esta pregunta, todavía estaría buscando manualmente mis blobs json increíblemente complejos (para los cuales no siempre creé la estructura) para fechas y serializándolos 1 por 1. - rebotes
19
Esta Q se repite una y otra vez: una forma sencilla de parchear el módulo json de modo que la serialización admita la fecha y la hora.
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Luego use la serialización json como siempre lo hace, esta vez con la fecha y hora serializada como isoformato.
json.dumps({'created':datetime.datetime.now()})
Resultando en: '{"creado": "2015-08-26T14:21:31.853855"}'
Vea más detalles y algunas palabras de advertencia en: StackOverflow: fecha y hora JSON entre Python y JavaScript
contestado el 23 de mayo de 17 a las 13:05
Parche de mono FTW. Lo desagradable es, por supuesto, que esto modifica el comportamiento del módulo json en toda su aplicación, lo que puede sorprender a otros en una aplicación grande, por lo que generalmente debe usarse con cuidado en mi humilde opinión. - Jaap Versteegh
7
En realidad es bastante simple. Si necesita serializar fechas con frecuencia, trabaje con ellas como cadenas. Puede volver a convertirlos fácilmente como objetos de fecha y hora si es necesario.
Si necesita trabajar principalmente como objetos de fecha y hora, conviértalos como cadenas antes de serializar.
import json, datetime
date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>
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))
<class 'datetime.datetime'>
Como puede ver, la salida es la misma en ambos casos. Sólo el tipo es diferente.
Respondido el 01 de diciembre de 18 a las 14:12
6
Pruebe este con un ejemplo para analizarlo:
#!/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()
Respondido 22 Jul 18, 07:07
11
Debe proporcionar una clase de codificador personalizado con el cls
parámetro de json.dumps
. Para citar del documentos:
>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
... def default(self, obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']
Esto usa números complejos como ejemplo, pero puede crear fácilmente una clase para codificar fechas (excepto que creo que JSON es un poco confuso con las fechas)
Respondido 09 ago 12, 04:08
7
La forma más sencilla de hacer esto es cambiar la parte del dictado que está en formato de fecha y hora a formato iso. Ese valor será efectivamente una cadena en formato iso con el que json está bien.
v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
Respondido el 30 de junio de 15 a las 19:06
2
Según la respuesta de @jjmontes, he usado el siguiente enfoque. Para usuarios de petacas y de petacas
# get json string
jsonStr = json.dumps(my_dictionary, indent=1, sort_keys=True, default=str)
# then covert json string to json object
return json.loads(jsonStr)
contestado el 02 de mayo de 21 a las 07:05
Esto no es distinto de la Respuesta de jjmontes; en su lugar, debería ser un comentario sobre su Respuesta. - cellepo
11
Aquí hay una solución simple para superar el problema de "datetime not JSON serializable".
enco = lambda obj: (
obj.isoformat()
if isinstance(obj, datetime.datetime)
or isinstance(obj, datetime.date)
else None
)
json.dumps({'date': datetime.datetime.now()}, default=enco)
Salida:-> {"date": "2015-12-16T04:48:20.024609"}
Respondido el 16 de diciembre de 15 a las 03:12
21
Tengo una aplicación con un problema similar; mi enfoque fue JSONize el valor de fecha y hora como una lista de 6 elementos (año, mes, día, hora, minutos, segundos); podría ir a microsegundos como una lista de 7 elementos, pero no tuve necesidad de:
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
encoded_object = list(obj.timetuple())[0:6]
else:
encoded_object =json.JSONEncoder.default(self, obj)
return encoded_object
sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()
print sample
print json.dumps(sample, cls=DateTimeEncoder)
produce:
{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}
Respondido 02 ago 13, 00:08
No funciona si el tiempo guardado se guarda haciendo datetime.utcnow() - Saurshaz
¿Qué error ve con datetime.utcnow()? Funciona bien para mí. - codificación
2
Mi solución ...
from datetime import datetime
import json
from pytz import timezone
import pytz
def json_dt_serializer(obj):
"""JSON serializer, by macm.
"""
rsp = dict()
if isinstance(obj, datetime):
rsp['day'] = obj.day
rsp['hour'] = obj.hour
rsp['microsecond'] = obj.microsecond
rsp['minute'] = obj.minute
rsp['month'] = obj.month
rsp['second'] = obj.second
rsp['year'] = obj.year
rsp['tzinfo'] = str(obj.tzinfo)
return rsp
raise TypeError("Type not serializable")
def json_dt_deserialize(obj):
"""JSON deserialize from json_dt_serializer, by macm.
"""
if isinstance(obj, str):
obj = json.loads(obj)
tzone = timezone(obj['tzinfo'])
tmp_dt = datetime(obj['year'],
obj['month'],
obj['day'],
hour=obj['hour'],
minute=obj['minute'],
second=obj['second'],
microsecond=obj['microsecond'])
loc_dt = tzone.localize(tmp_dt)
deserialize = loc_dt.astimezone(tzone)
return deserialize
Bien, ahora algunas pruebas.
# Tests
now = datetime.now(pytz.utc)
# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True
# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True
# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
print(tmp)
# 2015-10-22 09:18:33.169302-04:00
print(now)
# 2015-10-22 09:18:33.169302-04:00
# Wow, Works!
assert tmp == now
Respondido 22 Oct 15, 14:10
2
En general, hay varias formas de serializar fechas y horas, como:
- Cadena ISO, corta y puede incluir información de la zona horaria, por ejemplo, @jgbarah's https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be
- Marca de tiempo (se pierden los datos de la zona horaria), por ejemplo, @JayTaylor's https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be
- Diccionario de propiedades (incluida la zona horaria).
Si está de acuerdo con la última forma, el trucos_json el paquete maneja fechas, horas y fechas y horas, incluidas las zonas horarias.
from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)
lo que da:
{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}
Así que todo lo que necesitas hacer es
`pip install json_tricks`
y luego importar desde json_tricks
en lugar de json
.
La ventaja de no almacenarlo como una sola cadena, int o float surge al decodificar: si encuentra solo una cadena o especialmente int o float, necesita saber algo sobre los datos para saber si es una fecha y hora. Como dictado, puede almacenar metadatos para que puedan ser decodificados automáticamente, que es lo que json_tricks
hace por ti También es fácilmente editable para humanos.
Descargo de responsabilidad: está hecho por mí. Porque yo tenía el mismo problema.
contestado el 23 de mayo de 17 a las 13:05
1
Si está en ambos lados de la comunicación, puede usar repr () y eval () funciona junto con json.
import datetime, json
dt = datetime.datetime.now()
print("This is now: {}".format(dt))
dt1 = json.dumps(repr(dt))
print("This is serialised: {}".format(dt1))
dt2 = json.loads(dt1)
print("This is loaded back from json: {}".format(dt2))
dt3 = eval(dt2)
print("This is the same object as we started: {}".format(dt3))
print("Check if they are equal: {}".format(dt == dt3))
No debe importar fecha y hora como
from datetime import datetime
ya que eval se quejará. O puede pasar datetime como parámetro para evaluar. En cualquier caso, esto debería funcionar.
Respondido 08 ago 18, 13:08
2
Convertir el date
a string
date = str(datetime.datetime(somedatetimehere))
Respondido 01 Feb 16, 06:02
La respuesta de jjmontes hace exactamente eso, pero sin la necesidad de hacerlo explícitamente para cada fecha... - veranosazules
2
Aquí está mi solución completa para convertir datetime a JSON y viceversa.
import calendar, datetime, json
def outputJSON(obj):
"""Default JSON serializer."""
if isinstance(obj, datetime.datetime):
if obj.utcoffset() is not None:
obj = obj - obj.utcoffset()
return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
return str(obj)
def inputJSON(obj):
newDic = {}
for key in obj:
try:
if float(key) == int(float(key)):
newKey = int(key)
else:
newKey = float(key)
newDic[newKey] = obj[key]
continue
except ValueError:
pass
try:
newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
continue
except TypeError:
pass
newDic[str(key)] = obj[key]
return newDic
x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}
print x
with open('my_dict.json', 'w') as fp:
json.dump(x, fp, default=outputJSON)
with open('my_dict.json') as f:
my_dict = json.load(f, object_hook=inputJSON)
print my_dict
Salida
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
Archivo JSON
{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}
Esto me ha permitido importar y exportar cadenas, enteros, flotantes y objetos de fecha y hora. No debería ser demasiado difícil de extender para otros tipos.
Respondido el 12 de enero de 16 a las 04:01
Explota en Python 3 con TypeError: 'str' does not support the buffer interface
. es por 'wb'
modo abierto, debe ser 'w'
. También sopla en la deserialización cuando tenemos datos similares a la fecha como '0000891618-05-000338'
pero no coincide con el patrón. - omikron
2
Si está utilizando el resultado en una vista, asegúrese de devolver una respuesta adecuada. Según la API, jsonify hace lo siguiente:
Crea una respuesta con la representación JSON de los argumentos proporcionados con un tipo MIME application/json.
Para imitar este comportamiento con json.dumps, debe agregar algunas líneas adicionales de código.
response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
También debe devolver un dictado para replicar completamente la respuesta de jsonify. Entonces, todo el archivo se verá así
from flask import make_response
from json import JSONEncoder, dumps
class CustomEncoder(JSONEncoder):
def default(self, obj):
if set(['quantize', 'year']).intersection(dir(obj)):
return str(obj)
elif hasattr(obj, 'next'):
return list(obj)
return JSONEncoder.default(self, obj)
@app.route('/get_reps/', methods=['GET'])
def get_reps():
sample = ['some text', <datetime object>, 123]
response = make_response(dumps({'result': sample}, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
Respondido el 09 de junio de 13 a las 14:06
La pregunta no tiene nada que ver con el matraz. - zoran pavlovic
La pregunta es sobre Python. Mi respuesta resuelve la pregunta usando python. El OP no dijo si la solución debería incluir o excluir ciertas bibliotecas. También es útil para cualquier otra persona que lea esta pregunta y quiera una alternativa a pymongo
. - rubano
La pregunta es sobre Python y no sobre Frasco. Flask ni siquiera es necesario en su respuesta a la pregunta, por lo que le sugiero que lo elimine. - zoran pavlovic
En matraz es mucho más fácil de usar. flask.json.dumps
maneja objetos de fecha y hora. - Jonatan
-2
Puede que no sea 100% correcto, pero esta es la forma más sencilla de serializar
#!/usr/bin/python
import datetime,json
sampledict = {}
sampledict['a'] = "some string"
sampledict['b'] = datetime.datetime.now()
print sampledict # output : {'a': 'some string', 'b': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)}
#print json.dumps(sampledict)
'''
output :
Traceback (most recent call last):
File "./jsonencodedecode.py", line 10, in <module>
print json.dumps(sampledict)
File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable
'''
sampledict['b'] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p")
afterdump = json.dumps(sampledict)
print afterdump #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"}
print type(afterdump) #<type 'str'>
afterloads = json.loads(afterdump)
print afterloads # output : {u'a': u'some string', u'b': u'April 15, 2017 05:18 AM'}
print type(afterloads) # output :<type 'dict'>
Respondido 15 Abr '17, 09:04
1
Recibí el mismo mensaje de error al escribir el decorador de serialización dentro de una Clase con sqlalchemy. Así que en lugar de:
Class Puppy(Base):
...
@property
def serialize(self):
return { 'id':self.id,
'date_birth':self.date_birth,
...
}
Simplemente tomé prestada la idea de jgbarah de usar isoformat() y agregué el valor original con isoformat(), de modo que ahora se ve así:
...
'date_birth':self.date_birth.isoformat(),
...
Respondido el 02 de diciembre de 15 a las 22:12
1
Una solución rápida si desea su propio formato
for key,val in sample.items():
if isinstance(val, datetime):
sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)
contestado el 24 de mayo de 16 a las 14:05
0
Me encontré con el mismo problema al externalizar el objeto del modelo django para volcarlo como JSON. Así es como puedes resolverlo.
def externalize(model_obj):
keys = model_obj._meta.get_all_field_names()
data = {}
for key in keys:
if key == 'date_time':
date_time_obj = getattr(model_obj, key)
data[key] = date_time_obj.strftime("%A %d. %B %Y")
else:
data[key] = getattr(model_obj, key)
return data
Respondido 20 Jul 13, 18:07
0
def j_serial(o): # self contained
from datetime import datetime, date
return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None
Uso de la utilidad anterior:
import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
print(serial_d) # output: 2018-02-28 02:23:15
Respondido 27 Feb 18, 20:02
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python json or haz tu propia pregunta.
¿Es esto específicamente Python en general, o posiblemente Django? - jdi
Técnicamente es específicamente python, no estoy usando django, sino recuperando registros de mongodb. - Rolando
posible duplicado de Fecha y hora JSON entre Python y JavaScript - jdi
Estoy usando mongoengine, pero si pymongo tiene mejores formas de evitar esto o superarlo, por favor dígalo. - Rolando
La pregunta vinculada esencialmente le dice que no intente serializar el objeto de fecha y hora, sino que lo convierta en una cadena en el formato ISO común antes de serializar. - Thomas Kelley