How to add weekly timedeltas with regards to dayli

2020-06-12 04:44发布

问题:

I want to add or subtract weeks (or days or month or years) to localized datetime objects. The problem is, that the naive approach will result in 1 hour shifts due to daylight saving timezones.

2014-03-27 12:00 is right before the switch from winter to summer time. If I add a timedelta of one week to this date localized in timezone Europe/Berlin for example, the result will be 2014-04-03 13:00. I would like to have the same hour of day, 2014-04-03 12:00. I found a solution:

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)

I was wondering if there is more generic/better solution. Are there any libraries that could solve this? This seems to be a pretty common issue.

回答1:

timedelta(days=7) means 7 days, as in 7*24 hours - not "solar days". If you add 7 days to a timezone-aware datetime, you'll obtain a datetime that is 7 days later - independently of how that datetime is represented in the timezone.

It seems what you really want is to apply the delta to the time you specified, ignoring timezone details. Notice the difference:

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

So, if possible, apply the deltas to the datetimes before they are localized.