python - mexico - pytz timezone list
¿Cómo obtengo la hora UTC de "medianoche" para una zona horaria determinada? (4)
Cada zona horaria tiene un número, por ejemplo, US / Central = -6. Esto se define como el desplazamiento en horas desde UTC. Como 0000 es medianoche, puede usar este desplazamiento para encontrar la hora en cualquier zona horaria cuando sea la medianoche UTC. Para acceder a eso, creo que puedes usar
time.timezone
Según The Python Docs , time.timezone realmente da el valor negativo de este número:
time.timezone
El desplazamiento de la zona horaria local (no DST), en segundos al oeste de UTC (negativo en la mayoría de Europa occidental, positivo en los EE. UU., Cero en el Reino Unido).
Entonces, simplemente usaría ese número por el tiempo en horas si es positivo (es decir, si es medianoche en Chicago (que tiene un valor de zona horaria +6), entonces es 6000 = 6 a.m. UTC).
Si el número es negativo, reste de 24. Por ejemplo, Berlín daría -1, entonces 24 - 1 => 2300 = 11pm.
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, obtenga la hora actual (en UTC), conviértala a alguna otra zona horaria, establezca la hora a medianoche y luego vuelva a convertir a UTC.
No solo estoy usando now () o localtime () ya que usaría la zona horaria del servidor, no la zona horaria del usuario.
No puedo evitar sentir que me estoy perdiendo algo, alguna idea?
Creo que puedes depurar algunas llamadas a métodos si lo haces así:
>>> 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 mayor que la estética en su código: dará el resultado incorrecto el día del cambio hacia o desde el horario de verano.
La razón de esto es que ni los constructores de fecha y hora ni replace()
tienen en cuenta los cambios de horario de verano.
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 para tz.localize()
indica:
Este método se debe usar para construir localtimes, en lugar de pasar un argumento tzinfo a un constructor datetime.
Por lo tanto, su 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
Sin embargo, no hay garantías para fechas anteriores a 1582.
La configuración de la variable de entorno TZ modifica las funciones de fecha y hora de la zona horaria de Python.
>>> 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)
La respuesta de @ hop es incorrecta el día de la transición del horario de verano (Daylight Saving Time, DST), por ejemplo, 1 de abril de 2012. Para solucionarlo, se puede usar tz.localize()
:
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)