biblioteca - strftime python
Python: dada la hora actual en UTC, ¿cómo se determina la hora de inicio y finalización del día en una zona horaria en particular? (4)
Creo que está obteniendo este resultado porque está agregando un día en lugar de 86400 segundos. No existe una equivalencia uniforme, siempre correcta entre días y segundos. Por ejemplo, si pytz
fuerce un día a "realmente" ser 86400 segundos, entonces agregar un día a una fecha del 31 de diciembre o 30 de junio a veces hará que el campo de segundos del resultado esté "un segundo apagado", porque en algunos años esos días han tenido 86401 segundos. (Es posible que tengan 86402 o incluso 86399 segundos en el futuro).
Por lo tanto, agregar un día significa simplemente aumentar el día en uno, llevando a mes y año si es necesario, pero sin cambiar los campos de hora del día. Intente agregar 86400 segundos y vea si obtiene el resultado deseado.
Estoy jugando con Google App Engine y me enteré de que la zona horaria está fijada en UTC. Deseo determinar la hora de inicio y finalización del día actual para la zona horaria local del usuario. Básicamente, dada la hora actual en UTC, ¿cómo se determina la hora de inicio y finalización del día actual, teniendo en cuenta los cambios en el horario de verano?
Tengo un código de ejemplo torpe. Tenga en cuenta que me doy cuenta de que si estoy especificando manualmente una fecha, también podría especificar la fecha de mañana, pero son ejemplos y quiero determinarlo de forma programática. Mi problema principal es que si agrego un timedelta a un datetime con una zona horaria y luego lo normalizo (como se sugiere en los documentos de pytz) obtengo un datetime que es una hora libre durante los cambios de horario de verano.
No se menciona en el código, pero en última instancia, el objetivo es convertir estos tiempos a UTC, por lo que es importante ser consciente de la zona horaria.
#!/usr/bin/python
import datetime
from pytz.gae import pytz
hobart_tz = pytz.timezone(''Australia/Hobart'')
utc_dt = pytz.utc.localize(datetime.datetime.utcnow())
hobart_dt = utc_dt.astimezone(hobart_tz)
# create a new datetime for the start of the day and add a day to it to get tomorrow.
today_start = datetime.datetime(hobart_dt.year, hobart_dt.month, hobart_dt.day)
today_start = hobart_tz.localize(today_start)
today_end = hobart_tz.normalize(today_start + datetime.timedelta(days=1))
print ''today:'', today_start
print '' next:'', today_end
print
# gives:
# today: 2011-08-28 00:00:00+10:00
# next: 2011-08-29 00:00:00+10:00
# but say today is a daylight savings changeover.
# after normalisation, we are off by an hour.
dst_finish_2011 = datetime.datetime(2011, 4, 3) # this would come from hobart_dt
dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
next = hobart_tz.normalize(dst_finish_2011 + datetime.timedelta(days=1))
print ''2011-04-03:'', dst_finish_2011
print ''2011-04-04:'', next # expect 2011-04-04 00:00:00+10:00
print
# gives
# 2011-04-03: 2011-04-03 00:00:00+11:00
# 2011-04-04: 2011-04-03 23:00:00+10:00 (wrong)
dst_start_2011 = datetime.datetime(2011, 10, 2) # this would come from hobart_dt
dst_start_2011 = hobart_tz.localize(dst_start_2011)
next = hobart_tz.normalize(dst_start_2011 + datetime.timedelta(days=1))
print ''2011-10-02:'', dst_start_2011
print ''2011-10-03:'', next # expect 2011-10-03 00:00:00+11:00
print
# gives
# 2011-10-02: 2011-10-02 00:00:00+10:00
# 2011-10-03: 2011-10-03 01:00:00+11:00 (wrong)
# I guess we could ignore the timezone and localise *after* ?
dst_finish_2011 = datetime.datetime(2011, 4, 3) # this would come from hobart_dt
next = dst_finish_2011 + datetime.timedelta(days=1)
# now localise
dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
next = hobart_tz.localize(next)
print ''2011-04-03:'', dst_finish_2011
print ''2011-04-04:'', next # expect 2011-04-04 00:00:00+10:00
print
# gives
# 2011-04-03: 2011-04-03 00:00:00+11:00
# 2011-04-04: 2011-04-04 00:00:00+10:00
Después de un poco de experimentación y pensamiento, creo que tengo una solución para ti. Mi respuesta anterior no era correcta como usted señaló; un objeto timedelta para days = 1 es básicamente el mismo que para seconds = 86400 (excepto cuando se trata de segundos intercalares).
Una forma, como recomendaría, de incrementar la fecha sin tener en cuenta la hora del día es usar un objeto datetime.date
lugar de un objeto datetime.datetime
:
>>> oneday = datetime.timedelta(days=1)
>>> d = datetime.date(2011,4,3)
>>> str(d + oneday)
''2011-04-04''
La hora del día podría agregarse para formar un objeto datetime.datetime
completo en el que sepa que los campos de la hora del día no se alteran con respecto a su valor original.
Otro método, uno que me sentiría seguro de usar, es trabajar temporalmente con fechas "ingenuas". De esta forma, no se aplicará una política de zona horaria al agregar el timedelta
.
>>> hob = pytz.timezone(''Australia/Hobart'')
>>> dstlast = datetime.datetime(2011,4,3)
>>> str(dstlast)
''2011-04-03 00:00:00''
>>> dstlasthob = hob.localize(dstlast)
>>> str(dstlasthob)
''2011-04-03 00:00:00+11:00''
>>> oneday = datetime.timedelta(days=1)
>>> str(hob.normalize(dstlasthob + oneday))
''2011-04-03 23:00:00+10:00''
>>> nextday = hob.localize(dstlasthob.replace(tzinfo=None) + oneday)
>>> str(nextday)
''2011-04-04 00:00:00+10:00''
Probé este método para las fechas que tienen segundos intercalares (un ejemplo es 2008-12-31) y el resultado tiene la hora del día 00:00:00. Lo cual puede ser incorrecto, no estoy seguro, pero es lo que quieres :-)
El siguiente código intenta obtener una hora de medianoche; si el ajuste de zona horaria lo hace fallar, se reajusta a la medianoche con el nuevo desplazamiento de zona.
def DayStartEnd(localized_dt):
tz = localized_dt.tzinfo
start = tz.normalize(datetime.datetime(localized_dt.year,localized_dt.month,localized_dt.day,0,0,0,0,tz))
after_midnight = start.hour*60*60 + start.minute*60 + start.second
if start.day != localized_dt.day:
start += datetime.timedelta(seconds = 24*60*60 - after_midnight)
elif after_midnight != 0:
start -= datetime.timedelta(seconds = after_midnight)
end = tz.normalize(start + datetime.timedelta(hours=24))
after_midnight = end.hour*60*60 + end.minute*60 + end.second
if end.day == localized_dt.day:
end += datetime.timedelta(seconds = 24*60*60 - after_midnight)
elif after_midnight != 0:
end -= datetime.timedelta(seconds = after_midnight)
return start,end
>>> hobart_tz = pytz.timezone(''Australia/Hobart'')
>>> dst_finish_2011 = datetime.datetime(2011, 4, 3)
>>> dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
>>> start,end = DayStartEnd(dst_finish_2011)
>>> print start,end
2011-04-03 00:00:00+11:00 2011-04-04 00:00:00+10:00
>>> dst_start_2011 = datetime.datetime(2011, 10, 2)
>>> dst_start_2011 = hobart_tz.localize(dst_start_2011)
>>> start,end = DayStartEnd(dst_start_2011)
>>> print start,end
2011-10-02 00:00:00+10:00 2011-10-03 00:00:00+11:00
Para saber la hora de inicio del día (medianoche) y la hora del final del día (mañana) en la zona horaria local, conociendo la hora UTC:
#!/usr/bin/env python
from datetime import datetime, time, timedelta
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal
tz = get_localzone() # get the local timezone as pytz.timezone
now = datetime.now(pytz.utc) # some UTC time
dt = now.astimezone(tz) # the same time in the local timezone
today = dt.date() # today in the local timezone (naive date object)
midnight = datetime.combine(today, time()) # midnight in the local timezone
aware_midnight = tz.localize(midnight, is_dst=None) # raise exception
# for ambiguous or
# non-existing
# times
tomorrow = midnight + timedelta(1)
aware_tomorrow = tz.localize(tomorrow, is_dst=None)
def print_time(aware_dt, fmt="%Y-%m-%d %H:%M:%S %Z%z"):
print(aware_dt.strftime(fmt))
utc_dt = aware_dt.astimezone(pytz.utc) # the same time in UTC
print(utc_dt.strftime(fmt))
print_time(aware_midnight)
print_time(aware_tomorrow)
Salida
2014-09-01 00:00:00 EST+1000
2014-08-31 14:00:00 UTC+0000
2014-09-02 00:00:00 EST+1000
2014-09-01 14:00:00 UTC+0000
Ver también,
- ¿Cómo obtengo la hora UTC de "medianoche" para una zona horaria determinada? - solo medianoche (no mañana)
- ¿Cómo puedo restar un día de una fecha python? - sobre la diferencia entre hace un día y ayer
- python - datetime con timezone to epoch - demuestra cuán fácil es producir una respuesta incorrecta (para algunas fechas, zonas horarias).