El formato ISO del objeto de fecha y hora UTC de Python no incluye Z (Zulu o desplazamiento cero)

9 minutos de lectura

avatar de usuario
Murali Mopurú

¿Por qué python 2.7 no incluye el carácter Z (Zulu o desplazamiento cero) al final de la cadena de isoformato del objeto de fecha y hora UTC a diferencia de JavaScript?

>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'

mientras que en javascript

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z

  • Los valores de fecha y hora de Python NO tienen información de zona horaria. Pruebe pytz o Babel si desea que la información de la zona horaria se almacene en su marca de tiempo.

    – tnknepp

    12 de diciembre de 2013 a las 16:06

  • datetime.datetime.utcnow().isoformat() + 'Z'

    – jfs

    17 de mayo de 2014 a las 3:23

  • Relacionado: ¿Cómo obtener una cadena de fecha y hora de formato iso que incluya la zona horaria predeterminada?

    – jfs

    5/10/2016 a las 19:40

  • ..y la falta de Z sorprendentemente hace que algunas cosas no funcionen, por ejemplo, la llamada a la API

    – cardamomo

    20 de marzo de 2017 a las 15:32

  • Se pone aún peor, si la última parte de datetime es 0, lo truncará…

    – NTG

    25 de mayo de 2020 a las 8:25

avatar de usuario
Manav Kataria

Opción: isoformat()

de pitón datetime no apoya la zona horaria militar sufijos como el sufijo ‘Z’ para UTC. El siguiente reemplazo de cadena simple hace el truco:

In [1]: import datetime

In [2]: d = datetime.datetime(2014, 12, 10, 12, 0, 0)

In [3]: str(d).replace('+00:00', 'Z')
Out[3]: '2014-12-10 12:00:00Z'

str(d) es esencialmente lo mismo que d.isoformat(sep=' ')

Ver: Fecha y hora, biblioteca estándar de Python

Opción: strftime()

O podrías usar strftime para lograr el mismo efecto:

In [4]: d.strftime('%Y-%m-%dT%H:%M:%SZ')
Out[4]: '2014-12-10T12:00:00Z'

Nota: esta opción solo funciona cuando sabe que la fecha especificada está en UTC.

Ver: fechahora.strftime()


Adicional: Zona horaria legible por humanos

Yendo más allá, puede estar interesado en mostrar información de zona horaria legible por humanos, pytz con strftime %Z bandera de zona horaria:

In [5]: import pytz

In [6]: d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=pytz.utc)

In [7]: d
Out[7]: datetime.datetime(2014, 12, 10, 12, 0, tzinfo=<UTC>)

In [8]: d.strftime('%Y-%m-%d %H:%M:%S %Z')
Out[8]: '2014-12-10 12:00:00 UTC'

  • ¿No debería ser el separador T en lugar de un espacio en blanco?

    – Marcello Romaní

    30 de marzo de 2019 a las 10:19

  • debería ser d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc) en la línea 2. Por cierto, en RFC3339 dice que un espacio está ‘bien’ (en lugar de la ‘T’).

    – FObersteiner

    9 de junio de 2020 a las 7:29


avatar de usuario
stiv

Pitón datetime los objetos no tienen información de zona horaria de forma predeterminada y, sin ella, Python infringe la especificación ISO 8601 (si no se proporciona información de la zona horaria, se supone que es la hora local). Puedes usar el paquete pytz para obtener algunas zonas horarias predeterminadas, o directamente subclase tzinfo tú mismo:

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)

Luego puede agregar manualmente la información de la zona horaria a utcnow():

>>> datetime.utcnow().replace(tzinfo=simple_utc()).isoformat()
'2014-05-16T22:51:53.015001+00:00'

Tenga en cuenta que esto SÍ se ajusta al formato ISO 8601, que permite Z o +00:00 como sufijo de UTC. Tenga en cuenta que este último en realidad se ajusta mejor al estándar, con la forma en que se representan las zonas horarias en general (UTC es un caso especial).

  • como incluyo Z en vez de +00:00 ?

    – leopoodle

    9 de febrero de 2017 a las 23:32

  • ¡¡¡ADVERTENCIA!!! pytz viola Python tzinfo protocolo y es peligroso de usar! Ver blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html

    – ivan_pozdeev

    10 de mayo de 2019 a las 9:44

  • @ivan_pozdeev gracias por el enlace, muy interesante. Tenga en cuenta que los cambios que permiten dateutil para trabajar no se implementaron hasta Python 3.6 con PEP 495, por así decirlo pytz no usó la interfaz estándar es injusto porque la interfaz cambió. Antes del cambio, la única forma de hacerlo funcionar era la forma pytz lo hizo.

    – Mark Ransom

    30 de octubre de 2019 a las 1:31

avatar de usuario
Elevador de arcilla

Los siguientes scripts de javascript y python dan resultados idénticos. Creo que es lo que estás buscando.

JavaScript

new Date().toISOString()

Pitón

from datetime import datetime

datetime.utcnow().isoformat()[:-3]+'Z'

La salida que dan es la hora UTC (zulú) formateada como una cadena ISO con un dígito significativo de 3 milisegundos y anexada con una Z.

2019-01-19T23:20:25.459Z

  • Pero si now() es 0 milisegundos, minutos y : también será despojado.

    – Mijaíl Murugov

    23 de noviembre de 2020 a las 14:00

  • @МихаилМуругов cuando corres .isoformat()crea una cadena con un número fijo de caracteres, incluidos los ceros finales, por lo que funciona de manera confiable

    – Peter Vander Meer

    19 de febrero de 2021 a las 16:09


  • @PeterVanderMeer datetime(2021, 2, 19, 23, 21, 15).isoformat() -> '2021-02-19T23:21:15', datetime(2021, 2, 19, 23, 21, 15, 256).isoformat() -> '2021-02-19T23:21:15.000256'. Diferentes representaciones. Mi error es que escribí sobre minutos, no segundos.

    – Mijaíl Murugov

    19 de febrero de 2021 a las 16:27

  • Con el desplazamiento de la zona horaria que necesita usar [:-6]+'Z'.

    – Gringo Suave

    4 de marzo de 2021 a las 2:53

avatar de usuario
poste alto

Su objetivo no debe ser agregar un carácter Z, debe ser generar una cadena de fecha y hora UTC “consciente” en formato ISO 8601. La solución es pasar un objeto de zona horaria UTC a datetime.now() En lugar de usar datetime.utcnow():

from datetime import datetime, timezone

datetime.now(timezone.utc)
>>> datetime.datetime(2020, 1, 8, 6, 6, 24, 260810, tzinfo=datetime.timezone.utc)

datetime.now(timezone.utc).isoformat()
>>> '2020-01-08T06:07:04.492045+00:00'

Que aspecto bien, así que vamos a ver lo que Django y dateutil pensar:

from django.utils.timezone import is_aware
is_aware(datetime.now(timezone.utc))
>>> True

from dateutil.parser import isoparse
is_aware(isoparse(datetime.now(timezone.utc).isoformat()))
>>> True

Tenga en cuenta que necesita usar isoparse() de dateutil.parser porque la documentación de Python para datetime.fromisoformat() dice que “no es compatible con el análisis de cadenas ISO 8601 arbitrarias”.

Bien, el pitón datetime tanto el objeto como la cadena ISO 8601 son UTC “conscientes”. Ahora veamos qué piensa JavaScript de la cadena de fecha y hora. Tomando prestado de esta respuesta obtenemos:

let date="2020-01-08T06:07:04.492045+00:00";
const dateParsed = new Date(Date.parse(date))

document.write(dateParsed);
document.write("\n");
// Tue Jan 07 2020 22:07:04 GMT-0800 (Pacific Standard Time)

document.write(dateParsed.toISOString());
document.write("\n");
// 2020-01-08T06:07:04.492Z

document.write(dateParsed.toUTCString());
document.write("\n");
// Wed, 08 Jan 2020 06:07:04 GMT

Notas:

Me acerqué a este problema con algunos objetivos:

  • generar una cadena de fecha y hora UTC “consciente” en formato ISO 8601
  • usar solamente Funciones de la biblioteca estándar de Python para la creación de cadenas y objetos de fecha y hora
  • validar el objeto de fecha y hora y la cadena con Django timezone función de utilidad, la dateutil funciones de analizador y JavaScript

Tenga en cuenta que este enfoque no es incluir un sufijo Z y no es usar utcnow(). Pero se basa en el recomendación en la documentación de Python y pasa la prueba tanto con Django como con JavaScript.

Ver también:

avatar de usuario
Zags

Respuesta corta

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")

Respuesta larga

La razón por la que la “Z” no está incluida es porque datetime.now() e incluso datetime.utcnow() devuelve fechas y horas ingenuas de zona horaria, es decir, fechas y horas sin información de zona horaria asociada. Para obtener una fecha y hora consciente de la zona horaria, debe pasar una zona horaria como argumento para datetime.now. Por ejemplo:

from datetime import datetime, timezone

datetime.utcnow()
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253)
# This is timezone naive

datetime.now(timezone.utc)
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253, tzinfo=datetime.timezone.utc)
# This is timezone aware

Una vez que tenga una marca de tiempo consciente de la zona horaria, el formato iso incluirá una designación de zona horaria. Por lo tanto, puede obtener una marca de tiempo ISO 8601 a través de:

datetime.now(timezone.utc).isoformat()
#> '2020-09-03T20:53:07.337670+00:00'

“+00:00” es una designación de zona horaria ISO 8601 válida para UTC. Si desea tener “Z” en lugar de “+00:00”, debe realizar el reemplazo usted mismo:

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
#> '2020-09-03T20:53:07.337670Z'

  • Me gusta esta respuesta porque la mayoría de los demás no demuestran agregar un Zo usar objetos de fecha y hora ingenuos. Siento que usar objetos conscientes es el camino a seguir. Una vez vi la diferencia entre datetime.utcnow().timestamp() y datetime.now(timezone.utc).timestamp() Decidí tratar de ceñirme a los objetos conscientes.

    –Jason Capriotti

    17 de abril de 2021 a las 2:00

  • Además, si realmente desea hacer coincidir el valor devuelto en Javascript, puede hacer esto: datetime.now(timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z'). Es un poco largo pero quizás también fácil de leer.

    –Jason Capriotti

    17 de abril de 2021 a las 2:07

  • Creo que esta es la mejor respuesta dadas las limitaciones de la API, pero esta biblioteca realmente debería tener un método para lograrlo. Reemplazar manualmente los componentes de las cuerdas para una operación muy común se siente frágil y debería ser innecesario.

    – Cartera

    10 oct 2021 a las 20:13


avatar de usuario
michel samia

En Python >= 3.2 puedes simplemente usar esto:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'

  • Me gusta esta respuesta porque la mayoría de los demás no demuestran agregar un Zo usar objetos de fecha y hora ingenuos. Siento que usar objetos conscientes es el camino a seguir. Una vez vi la diferencia entre datetime.utcnow().timestamp() y datetime.now(timezone.utc).timestamp() Decidí tratar de ceñirme a los objetos conscientes.

    –Jason Capriotti

    17 de abril de 2021 a las 2:00

  • Además, si realmente desea hacer coincidir el valor devuelto en Javascript, puede hacer esto: datetime.now(timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z'). Es un poco largo pero quizás también fácil de leer.

    –Jason Capriotti

    17 de abril de 2021 a las 2:07

  • Creo que esta es la mejor respuesta dadas las limitaciones de la API, pero esta biblioteca realmente debería tener un método para lograrlo. Reemplazar manualmente los componentes de las cuerdas para una operación muy común se siente frágil y debería ser innecesario.

    – Cartera

    10 oct 2021 a las 20:13


avatar de usuario
dima tisnek

Las fechas y horas de Python son un poco torpes. Usar arrow.

> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'

Arrow tiene esencialmente la misma API que datetime, pero con zonas horarias y algunas sutilezas adicionales que deberían estar en la biblioteca principal.

Se puede lograr un formato compatible con Javascript mediante:

arrow.utcnow().isoformat().replace("+00:00", "Z")
'2018-11-30T02:46:40.714281Z'

JavaScript Date.parse bajará silenciosamente microsegundos de la marca de tiempo.

  • Esto no responde la pregunta ya que la cadena no termina con ‘Z’.

    – kaleissin

    14 de junio de 2018 a las 8:26

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad