Como adicionar timedeltas semanais com relação a fusos horários de horário de verão

Eu quero adicionar ou subtrair semanas (ou dias ou meses ou anos) para objects datetime localizados. O problema é que a abordagem ingênua resultará em turnos de 1 hora devido aos fusos horários de horário de verão.

2014-03-27 12:00 está certo antes da mudança do inverno para o horário de verão. Se eu adicionar um timedelta de uma semana a esta data localizado no fuso horário Europa / Berlim, por exemplo, o resultado será 2014-04-03 13:00. Eu gostaria de ter a mesma hora do dia, 2014-04-03 12:00. Eu encontrei uma solução:

from datetime import datetime, timedelta import pytz my_tz = pytz.timezone("Europe/Berlin") def add_relativedelta(date, delta): """ Adds the given timedelta to the given date. Shifts in timezone offsets will be removed. """ tz = date.tzinfo result = tz.normalize(date + delta) if result.utcoffset() != date.utcoffset(): result = tz.normalize(date.utcoffset() - result.utcoffset() + result) return result date = my_tz.localize(datetime(year=2014, month=3, day=27, hour=12, minute=0)) print """{} Original localized date (winter time) {} One week later (summer time) {} Date one week later preserving hour of day (summer time)""".format(date, my_tz.normalize(date + timedelta(days=7)), add_relativedelta(date, timedelta(days=7))) 2014-03-27 12:00:00+01:00 Original localized date (winter time) 2014-04-03 13:00:00+02:00 One week later (summer time) 2014-04-03 12:00:00+02:00 Date one week later preserving hour of day (summer time) 

Eu queria saber se existe uma solução mais genérica / melhor. Existem bibliotecas que possam resolver isso? Este parece ser um problema bastante comum.

timedelta(days=7) significa 7 dias, como em 7*24 horas – não “dias solares”. Se você adicionar 7 dias a um datetime com reconhecimento de fuso horário, obterá um datetime que é 7 dias depois – independentemente de como esse datetime é representado no fuso horário.

Parece que o que você realmente quer é aplicar o delta ao horário especificado, ignorando os detalhes do fuso horário. Observe a diferença:

 In [13]: print my_tz.normalize( my_tz.localize( dt ) + delta ) 2014-04-03 13:00:00+02:00 In [14]: print my_tz.normalize( my_tz.localize( dt + delta ) ) 2014-04-03 12:00:00+02:00 

Portanto, se possível, aplique os deltas aos tempos de dados antes que eles sejam localizados.