¿Por qué datetime.datetime.utcnow () no contiene información de la zona horaria?

datetime.datetime.utcnow() 

¿Por qué esta datetime no tiene ninguna información de zona horaria dado que es explícitamente una datetime UTC?

Espero que esto contenga tzinfo .

Eso significa que es ingenuo para la zona horaria, por lo que no puede usarlo con datetime.astimezone

Puedes darle una zona horaria como esta

 import pytz # 3rd party: $ pip install pytz u = datetime.utcnow() u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset 

ahora puedes cambiar las zonas horarias

 print(u.astimezone(pytz.timezone("America/New_York"))) 

Para obtener la hora actual en una zona horaria determinada, puede pasar tzinfo a datetime.now() directamente:

 #!/usr/bin/env python from datetime import datetime import pytz # $ pip install pytz print(datetime.now(pytz.timezone("America/New_York"))) 

Funciona para cualquier zona horaria, incluidos los que observan el horario de verano (DST), es decir, funciona para zonas horarias que pueden tener diferentes desplazamientos de utc en diferentes momentos (desplazamiento de utc no fijo). No utilice tz.localize(datetime.now()) : puede fallar durante la transición de final del horario de verano cuando la hora local es ambigua.

Tenga en cuenta que para Python 3.2 en adelante, el módulo datetime.timezone contiene datetime.timezone . La documentación para datetime.utcnow() dice:

Se puede obtener un datetime UTC actual al llamar a datetime.now ( timezone.utc ) .

Así que puedes hacer:

 >>> import datetime >>> datetime.datetime.now(datetime.timezone.utc) datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc) 

Las bibliotecas estándar de Python no incluyen ninguna clase tzinfo (pero ver pep 431 ). Solo puedo adivinar las razones. Personalmente, creo que fue un error no incluir una clase tzinfo para UTC, porque esa no es lo suficientemente controvertida como para tener una implementación estándar.

Edición: Aunque no hay implementación en la biblioteca, hay una como ejemplo en la documentación de tzinfo .

 from datetime import timedelta, tzinfo ZERO = timedelta(0) # A UTC class. class UTC(tzinfo): """UTC""" def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO utc = UTC() 

Para usarlo, para obtener la hora actual como un objeto datetime consciente:

 from datetime import datetime now = datetime.now(utc) 

Hay datetime.timezone.utc en Python 3.2+:

 from datetime import datetime, timezone now = datetime.now(timezone.utc) 

El módulo pytz es una opción, y hay otro python-dateutil , que aunque también es un paquete de terceros, puede que ya esté disponible, dependiendo de sus otras dependencias y sistema operativo.

Solo quería incluir esta metodología como referencia: si ya ha instalado python-dateutil para otros propósitos, puede usar su tzinfo lugar de duplicar con pytz

 import datetime import dateutil.tz # Get the UTC time with datetime.now: utcdt = datetime.datetime.now(dateutil.tz.tzutc()) # Get the UTC time with datetime.utcnow: utcdt = datetime.datetime.utcnow() utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc()) # For fun- get the local time localdt = datetime.datetime.now(dateutil.tz.tzlocal()) 

utcnow a aceptar que las llamadas a utcnow deben incluir la información de la zona horaria UTC. Sospecho que esto no está incluido porque la biblioteca nativa de fecha y hora se establece de manera predeterminada en tiempos de datos ingenuos para compatibilidad cruzada.

Julien Danjou escribió un buen artículo que explica por qué nunca debes lidiar con las zonas horarias . Un experto:

De hecho, la API datetime de Python siempre devuelve los objetos datetime no conscientes, lo cual es muy desafortunado. De hecho, tan pronto como obtengas uno de este objeto, no hay forma de saber qué es la zona horaria, por lo que estos objetos son bastante “inútiles” por sí solos.

Por desgracia, aunque puedas usar utcnow() , aún no verás la información de la zona horaria, como descubriste.

Recomendaciones:

  • Utilice siempre objetos de datetime conscientes, es decir, con información de zona horaria. Eso asegura que pueda compararlos directamente (los objetos de datetime y datetime conscientes y no conscientes no son comparables) y los devolverá correctamente a los usuarios. Aproveche pytz para tener objetos de zona horaria.

  • Utilice ISO 8601 como el formato de cadena de entrada y salida. Use datetime.datetime.isoformat() para devolver las marcas de tiempo como una cadena formateada usando ese formato, que incluye la información de la zona horaria.

  • Si necesita analizar cadenas que contienen marcas de tiempo con formato ISO 8601, puede confiar en iso8601 , que devuelve las marcas de tiempo con la información de zona horaria correcta. Esto hace que las marcas de tiempo sean directamente comparables.

Para agregar información de la timezone en Python 3.2+

 import datetime >>> d = datetime.datetime.now(tz=datetime.timezone.utc) >>> print(d.tzinfo) 'UTC+00:00' 
 from datetime import datetime from dateutil.relativedelta import relativedelta d = datetime.now() date = datetime.isoformat(d).split('.')[0] d_month = datetime.today() + relativedelta(months=1) next_month = datetime.isoformat(d_month).split('.')[0] 

Las fechas UTC no necesitan ninguna información de la zona horaria, ya que son UTC, lo que por definición significa que no tienen compensación.