javascript - now - python parse date
JSON datetime entre Python y JavaScript (11)
Quiero enviar un objeto datetime.datetime en forma serializada desde Python usando JSON y des-serializar en JavaScript usando JSON. ¿Cuál es la mejor manera de hacer esto?
Al final del juego ... :)
Una solución muy simple es parchear el módulo json por defecto. Por ejemplo:
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Ahora, puede usar json.dumps () como si siempre hubiera soportado datetime ...
json.dumps({''created'':datetime.datetime.now()})
Esto tiene sentido si necesita que esta extensión del módulo json siempre se active y no desea cambiar la forma en que usted u otras personas usan la serialización json (ya sea en el código existente o no).
Tenga en cuenta que algunos pueden considerar parchear las bibliotecas de esa manera como una mala práctica. Se debe tener especial cuidado en caso de que desee extender su aplicación en más de una forma. En tal caso, le sugiero que use la solución de ramen o JT y elija la extensión json adecuada en cada caso.
Aparentemente, el formato de fecha JSON (bueno, JavaScript) es el 2012-04-23T18: 25: 43.511Z - UTC y "Z". Sin este JavaScript, utilizará la zona horaria local del navegador web al crear un objeto Date () a partir de la cadena.
Para una hora "ingenua" (lo que Python llama una hora sin zona horaria y se supone que es local), lo siguiente forzará la zona horaria local para que luego pueda convertirse correctamente a UTC:
def default(obj):
if hasattr(obj, "json") and callable(getattr(obj, "json")):
return obj.json()
if hasattr(obj, "isoformat") and callable(getattr(obj, "isoformat")):
# date/time objects
if not obj.utcoffset():
# add local timezone to "naive" local time
# https://.com/questions/2720319/python-figure-out-local-timezone
tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
obj = obj.replace(tzinfo=tzinfo)
# convert to UTC
obj = obj.astimezone(timezone.utc)
# strip the UTC offset
obj = obj.replace(tzinfo=None)
return obj.isoformat() + "Z"
elif hasattr(obj, "__str__") and callable(getattr(obj, "__str__")):
return str(obj)
else:
print("obj:", obj)
raise TypeError(obj)
def dump(j, io):
json.dump(j, io, indent=2, default=default)
Por qué es tan difícil.
Aquí hay una solución bastante completa para codificar y decodificar recursivamente objetos datetime.datetime y datetime.date usando el módulo json
biblioteca estándar. Esto necesita Python> = 2.6 ya que el código de formato %f
en la cadena de formato datetime.datetime.strptime () solo es compatible desde entonces. Para el soporte de Python 2.5, elimine el %f
y elimine los microsegundos de la cadena de fecha ISO antes de intentar convertirlo, pero perderá la precisión de los microsegundos, por supuesto. Para la interoperabilidad con cadenas de fecha ISO de otras fuentes, que pueden incluir un nombre de zona horaria o un desplazamiento UTC, es posible que también deba eliminar algunas partes de la cadena de fecha antes de la conversión. Para obtener un analizador completo de cadenas de fecha ISO (y muchos otros formatos de fecha), consulte el módulo dateutil terceros.
La decodificación solo funciona cuando las cadenas de fecha ISO son valores en una notación de objeto literal de JavaScript o en estructuras anidadas dentro de un objeto. Las cadenas de fecha ISO, que son elementos de una matriz de nivel superior, no se descodificarán.
Es decir, esto funciona:
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''}
Y esto también:
>>> 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)}]
Pero esto no funciona como se esperaba:
>>> 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'']
Aquí está el código:
__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))
En el lado de Python:
import time, json
from datetime import datetime as dt
your_date = dt.now()
data = json.dumps(time.mktime(your_date.timetuple())*1000)
return data # data send to javascript
En el lado de javascript:
var your_date = new Date(data)
donde los datos son resultado de Python
Lo he resuelto.
Digamos que tienes un objeto datetime de Python, d , creado con datetime.now (). Su valor es:
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
Puede serializarlo a JSON como una cadena datetime ISO 8601:
import json
json.dumps(d.isoformat())
El objeto datetime de ejemplo se serializaría como:
''"2011-05-25T13:34:05.787000"''
Este valor, una vez recibido en la capa de Javascript, puede construir un objeto Date:
var d = new Date("2011-05-25T13:34:05.787000");
A partir de Javascript 1.8.5, los objetos Date tienen un método toJSON, que devuelve una cadena en un formato estándar. Para serializar el objeto Javascript anterior a JSON, por lo tanto, el comando sería:
d.toJSON()
Lo que te daría:
''2011-05-25T20:34:05.787Z''
Esta cadena, una vez recibida en Python, podría deserializarse de nuevo a un objeto de fecha y hora:
datetime.strptime(''2011-05-25T20:34:05.787Z'', ''%Y-%m-%dT%H:%M:%S.%fZ'')
Esto da como resultado el siguiente objeto de fecha y hora, que es el mismo con el que comenzó y, por lo tanto, correcto:
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
Mi consejo es usar una biblioteca. Hay varios disponibles en pypi.org.
Yo uso este, funciona bien: https://pypi.python.org/pypi/asjson
No hay mucho que agregar a la respuesta de la wiki de la comunidad, excepto la marca de tiempo !
Javascript usa el siguiente formato:
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Lado de Python (para el controlador json.dumps
, consulte las otras respuestas):
>>> from datetime import datetime
>>> d = datetime.strptime(''2016-01-08T19:00:00.123Z'', ''%Y-%m-%dT%H:%M:%S.%fZ'')
>>> d
datetime.datetime(2016, 1, 8, 19, 0, 0, 123000)
>>> d.isoformat() + ''Z''
''2016-01-08T19:00:00.123000Z''
Si deja esa Z fuera, los marcos frontales como angular no pueden mostrar la fecha en la zona horaria local del navegador:
> $filter(''date'')(''2016-01-08T19:00:00.123000Z'', ''yyyy-MM-dd HH:mm:ss'')
"2016-01-08 20:00:00"
> $filter(''date'')(''2016-01-08T19:00:00.123000'', ''yyyy-MM-dd HH:mm:ss'')
"2016-01-08 19:00:00"
Para los proyectos en varios idiomas, descubrí que las cadenas que contienen fechas RfC 3339 son la mejor manera de hacerlo. Una fecha de RfC 3339 se ve así:
1985-04-12T23:20:50.52Z
Creo que la mayor parte del formato es obvio. La única cosa un tanto inusual puede ser la "Z" al final. Es sinónimo de GMT / UTC. También puede agregar un desplazamiento de zona horaria como +02: 00 para CEST (Alemania en verano). Personalmente prefiero mantener todo en UTC hasta que se muestre.
Para la visualización, comparaciones y almacenamiento, puede dejarlo en formato de cadena en todos los idiomas. Si necesita la fecha para los cálculos, puede volver a convertirla en un objeto de fecha nativa en la mayoría de los idiomas.
Así que genera el JSON de esta manera:
json.dump(datetime.now().strftime(''%Y-%m-%dT%H:%M:%SZ''))
Desafortunadamente, el constructor de fecha de Javascript no acepta cadenas RfC 3339 pero hay muchos parsers disponibles en Internet.
huTools.hujson trata de manejar los problemas de codificación más comunes con los que puede encontrarse en el código Python, incluidos los objetos de fecha / fecha, mientras se manejan las zonas horarias correctamente.
Puede agregar el parámetro ''predeterminado'' a json.dumps para manejar esto:
date_handler = lambda obj: (
obj.isoformat()
if isinstance(obj, (datetime.datetime, datetime.date))
else None
)
json.dumps(datetime.datetime.now(), default=date_handler)
''"2010-04-20T20:08:21.634121"''
Que es el formato ISO 8601 .
Una función de manejador por defecto más completa:
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))
Actualización: Se agregó salida de tipo así como valor.
Actualización: también manejar fecha
Si está seguro de que solo Javascript consumirá el JSON, prefiero pasar los objetos de Date
Javascript directamente.
El método ctime()
en objetos de datetime
devolverá una cadena que el objeto Fecha de Javascript puede comprender.
import datetime
date = datetime.datetime.today()
json = ''{"mydate":new Date("%s")}'' % date.ctime()
Javascript con mucho gusto lo usará como un objeto literal, y ya tienes tu objeto Date integrado.
Usando json
, puede crear una subclase de JSONEncoder y anular el método predeterminado () para proporcionar sus propios serializadores personalizados:
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)
Entonces, puedes llamarlo así:
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
''["2010-06-15T14:42:28"]''