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


120

¿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

1
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

67
datetime.datetime.utcnow().isoformat() + 'Z'
jfs


3
..y la Z faltante sorprendentemente hace que algunas cosas no funcionen, por ejemplo, llamada a la API
cardamomo

Se pone aún peor, si la última parte de datetime es 0, la truncará ...
ntg

Respuestas:


52

Los datetimeobjetos de Python no tienen información de zona horaria de forma predeterminada, y sin ella, Python en realidad viola la especificación ISO 8601 ( si no se proporciona información de zona horaria, se supone que es la hora local ). Puede usar el paquete pytz para obtener algunas zonas horarias predeterminadas, o directamente subclase tzinfousted 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 Zo +00:00como sufijo para 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).


108
¿Cómo incluyo en Zlugar de +00:00?
leopoodle

14
¡¡¡ADVERTENCIA!!! pytzviola el tzinfoprotocolo de Python y es peligroso de usar. Ver blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html
ivan_pozdeev

@ivan_pozdeev gracias por el enlace, muy interesante. Tenga en cuenta que los cambios que permiten dateutiltrabajar no se implementaron hasta Python 3.6 con PEP 495, por lo que decir pytzque no usó la interfaz estándar es injusto porque la interfaz cambió. Antes del cambio, la única forma de hacerlo funcionar era la forma en pytzque se hacía.
Mark Ransom

67

Opción: isoformat()

Python datetimeno admite los sufijos de zona horaria militar 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ía usar strftimepara lograr el mismo efecto:

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

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

Ver: datetime.strftime ()


Adicional: Zona horaria legible por humanos

Yendo más allá, es posible que le interese mostrar información de zona horaria legible por humanos, pytzcon la strftime %Zbandera 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'

1
¿No debería ser el separador en Tlugar de un espacio en blanco?
Marcello Romani

1
debería estar 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 es 'ok' (en lugar de la 'T').
MrFuppes

16

Los siguientes scripts de javascript y python dan resultados idénticos. Creo que es lo que buscas.

JavaScript

new Date().toISOString()

Pitón

import datetime

datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

La salida que dan es la hora utc (zelda) formateada como una cadena ISO con un dígito significativo de 3 milisegundos y adjuntada con una Z.

2019-01-19T23:20:25.459Z

12

En Python> = 3.2, simplemente puede usar esto:

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

3
Muy buena solucion. Para su pregunta sobre el Z, puede recortar el desplazamiento:.isoformat()[:-6] + 'Z'
Maximilian Burszley

11

Las fechas de Python son un poco torpes. Utilice 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.

Un formato compatible con Javascript se puede lograr mediante:

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

Javascript Date.parseeliminará silenciosamente microsegundos de la marca de tiempo.


7
Esto no responde a la pregunta ya que la cadena no termina con 'Z'.
kaleissin

3

Hay muchas buenas respuestas en la publicación, pero quería que el formato saliera exactamente como lo hace con JavaScript. Esto es lo que estoy usando y funciona bien.

In [1]: import datetime

In [1]: now = datetime.datetime.utcnow()

In [1]: now.strftime('%Y-%m-%dT%H:%M:%S') + now.strftime('.%f')[:4] + 'Z'
Out[3]: '2018-10-16T13:18:34.856Z'

3
pip install python-dateutil
>>> a = "2019-06-27T02:14:49.443814497Z"
>>> dateutil.parser.parse(a)
datetime.datetime(2019, 6, 27, 2, 14, 49, 443814, tzinfo=tzutc())

2

Abordé este problema con algunos objetivos:

  • generar una cadena de fecha y hora "consciente" de UTC en formato ISO 8601
  • use solo las funciones de la biblioteca estándar de Python para la creación de cadenas y objetos de fecha y hora
  • validar el objeto y la cadena de fecha y hora con una timezonefunción de utilidad Django y el dateutilanalizador
  • use funciones de JavaScript para validar que la cadena de fecha y hora ISO 8601 es compatible con UTC

Este enfoque no incluye un sufijo Z y no se usa utcnow(), pero se basa en la recomendación de la documentación de Python y se aprueba con Django y JavaScript.

Comencemos pasando un objeto de zona horaria UTC en datetime.now()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'

Eso se ve bien, así que veamos qué es Django y dateutilpensemos:

from django.utils.timezone import is_aware

is_aware(datetime.now(timezone.utc))
>>> True

import dateutil.parser

is_aware(dateutil.parser.parse(datetime.now(timezone.utc).isoformat()))
>>> True

Bien, el objeto de fecha y hora de Python y la cadena ISO 8601 son "compatibles" con UTC. 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

Es posible que también desee leer esta publicación de blog .


1
Bonificación por ceñirse a las funciones de la biblioteca base y seguir una publicación anterior.
Victor Romeo

1

Al combinar todas las respuestas anteriores, vine con la siguiente función:

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


def getdata(yy, mm, dd, h, m, s) :
    d = datetime(yy, mm, dd, h, m, s)
    d = d.replace(tzinfo=simple_utc()).isoformat()
    d = str(d).replace('+00:00', 'Z')
    return d


print getdata(2018, 02, 03, 15, 0, 14)

1

Yo uso péndulo:

import pendulum


d = pendulum.now("UTC").to_iso8601_string()
print(d)

>>> 2019-10-30T00:11:21.818265Z

0
>>> import arrow

>>> now = arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS')
>>> now
'2018-11-28T21:34:59.235'
>>> zulu = "{}Z".format(now)
>>> zulu
'2018-11-28T21:34:59.235Z'

O, para obtenerlo de una sola vez:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.