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.
I use this simple code without the need for other libraries:
from datetime import datetime, timedelta
from pytz import timezone
tz = timezone('Europe/Berlin')
dt = tz.localize(datetime(2014, 3, 27, 12))
week_naive = datetime.combine(dt.date() + timedelta(days=7), dt.time())
week_local = dt.tzinfo.localize(week_naive)
print(dt, "Original datetime")
print(week_local, "Next week datetime")
Outputs:
2014-03-27 12:00:00+01:00 Original datetime
2014-04-03 12:00:00+02:00 Next week datetime
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With