Pregunta

Lo mejor que se me ocurre por ahora es esta monstruosidad:

>>> datetime.utcnow() \
...   .replace(tzinfo=pytz.UTC) \
...   .astimezone(pytz.timezone("Australia/Melbourne")) \
...   .replace(hour=0,minute=0,second=0,microsecond=0) \
...   .astimezone(pytz.UTC) \
...   .replace(tzinfo=None)
datetime.datetime(2008, 12, 16, 13, 0)

es decir., En Inglés, obtener la hora actual (en UTC), convertirlo a alguna otra zona horaria, defina la hora de la medianoche, a continuación, convertir de nuevo a UTC.

No sólo estoy usando ahora () o localtime (), ya que ello utilizar la zona horaria del servidor, no la zona horaria del usuario.

No puedo evitar sentir que me falta algo, alguna idea?

¿Fue útil?

Solución

Creo que se puede afeitarse unas pocas llamadas de método si lo haces de esta manera:

>>> from datetime import datetime
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \
            .replace(hour=0, minute=0, second=0, microsecond=0) \
            .astimezone(pytz.utc)

PERO ... hay un problema más grande que la estética en su código:. Dará un resultado erróneo en el día del interruptor hacia o desde el horario de verano

La razón de esto es que ni los constructores ni de fecha y hora replace() toman el horario de verano cambia en cuenta.

Por ejemplo:

>>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne"))
>>> print now
2012-04-01 05:00:00+10:00
>>> print now.replace(hour=0)
2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00
>>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz)
2012-03-01 00:00:00+10:00 # wrong again!

Sin embargo, la documentación de los estados tz.localize():

  

Este método se debe utilizar para construir localtimes, en vez   de pasar un argumento tzinfo a un constructor de fecha y hora.

Por lo tanto, el problema se resuelve de esta manera:

>>> import pytz
>>> from datetime import datetime, date, time

>>> tz = pytz.timezone("Australia/Melbourne")
>>> the_date = date(2012, 4, 1) # use date.today() here

>>> midnight_without_tzinfo = datetime.combine(the_date, time())
>>> print midnight_without_tzinfo
2012-04-01 00:00:00

>>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo)
>>> print midnight_with_tzinfo
2012-04-01 00:00:00+11:00

>>> print midnight_with_tzinfo.astimezone(pytz.utc)
2012-03-31 13:00:00+00:00

No hay garantías para las fechas antes de 1582, sin embargo.

Otros consejos

@ hop respuesta está mal en el día de transición de horario de verano (DST), por ejemplo, Apr 1, 2012 . Para solucionarlo tz.localize() podría usarse:

tz = pytz.timezone("Australia/Melbourne")
today = datetime.now(tz).date()
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
utc_dt = midnight.astimezone(pytz.utc)        

Lo mismo con los comentarios:

#!/usr/bin/env python
from datetime import datetime, time
import pytz # pip instal pytz

tz = pytz.timezone("Australia/Melbourne") # choose timezone

# 1. get correct date for the midnight using given timezone.
today = datetime.now(tz).date()

# 2. get midnight in the correct timezone (taking into account DST)
#NOTE: tzinfo=None and tz.localize()
# assert that there is no dst transition at midnight (`is_dst=None`)
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)

# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no 
#    DST transitions)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print midnight.astimezone(pytz.utc).strftime(fmt)

Configuración de la variable de entorno TZ modifica lo que las funciones de fecha y hora de la zona horaria de Python trabajar con ellos.

>>> time.gmtime()
(2008, 12, 17, 1, 16, 46, 2, 352, 0)
>>> time.localtime()
(2008, 12, 16, 20, 16, 47, 1, 351, 0)
>>> os.environ['TZ']='Australia/Melbourne'
>>> time.localtime()
(2008, 12, 17, 12, 16, 53, 2, 352, 1)

Cada zona de tiempo tiene un número, por ejemplo, US / central = -6. Esto se define como el desplazamiento en horas de la UTC. Desde 0000 es la medianoche, sólo tiene que utilizar este desplazamiento para encontrar el tiempo en cualquier zona horaria cuando es medianoche UTC. Para acceder a esto, creo que se puede utilizar

 time.timezone

Según El Python Docs , time.timezone en realidad le da el valor negativo de este número:

  
    

time.timezone

         
      

El desplazamiento del local (no-DST) zona horaria, en cuestión de segundos al oeste de UTC (negativo en la mayor parte de Europa Occidental y positiva en los EE.UU., cero en el Reino Unido).

    
  

Así que sólo tendría que usar ese número para el tiempo en horas si es positivo (es decir, si se trata de la medianoche en Chicago (que tiene un valor de 6 zona horaria), entonces es 6000 = 06 a.m. GMT).

Si el número es negativo, restar de 24. Por ejemplo, Berlin daría -1, por lo que 24 -. 1 => 2300 = 23:00

Esto es más sencillo con dateutil.tz que pytz:

>>>import datetime
>>>import dateutil.tz
>>>midnight=(datetime.datetime
             .now(dateutil.tz.gettz('Australia/Melbourne'))
             .replace(hour=0, minute=0, second=0, microsecond=0)
             .astimezone(dateutil.tz.tzutc()))
>>>print(midnight)
2019-04-26 14:00:00+00:00

El tzinfo documentación recomienda dateutil.tz desde Python 3.6. Los objetos de tzinfo dateutil.tz no tienen problemas con anomalías como el horario de verano sin que se requiera la funcionalidad de localize pytz. Usando el ejemplo de user3850:

>>> now = (datetime.datetime(2012, 4, 1, 5,  
...         tzinfo = dateutil.tz.gettz('Australia/Melbourne'))) 
>>> print(now.replace(hour = 0).astimezone(dateutil.tz.tzutc()))
2012-03-31 13:00:00+00:00
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top