0

My problem is similar to this question, but doing the timedelta on UTC datetimes is not an option for me.

I have a function that evaluates a period every 'human day', so midnight-to-midnight. That means that in the UK for example, there are two days with 23 and 25 hours respectively. It works something like this:

import datetime
import pytz

start_dt = datetime.datetime(2016, 3, 27, 0, 0, 0, 0)
localtz = pytz.timezone('Europe/London')
start_dt = localtz.localize(start_dt)
print start_dt

end_dt = start_dt + datetime.timedelta(days=1)
print end_dt

print (end_dt - start_dt).total_seconds()

In the above snippet end_dt evaluates to 2016-03-28 00:00:00+00:00 and the timedelta is 86400. Shouldn't it be 2016-03-28 00:00:00+01:00 and 82800?

I've seen posts saying to use pytz function normalize() to 'normalize' the end_dt, but it just results in a end-dt of 2016-03-28 01:00:00+01:00

Community
  • 1
  • 1
user2819573
  • 161
  • 1
  • 9
  • The function add_relativedelta() in this [question](http://stackoverflow.com/questions/24673330/how-to-add-weekly-timedeltas-with-regards-to-daylight-saving-timezones) seems to handles both ambigious days in the London timezone, just not so sure if this is safe or Mark's answer below. Does either method cover half-hour timezones for example? This seems like something that should be builtin to python or pytz at least – user2819573 Jun 20 '16 at 15:43

1 Answers1

1

Add 25 hours and then reset the time. This works if the time is always midnight to midnight, but might fail at other times of day.

end_dt = start_dt + datetime.timedelta(hours=25)
end_dt = end_dt.replace(hour=0, minute=0, second=0)

A more robust solution uses a noon-to-noon calculation and replaces the time afterwards. This should work for any time of day and any timezone rules, and allows any arbitrary number of days (even negative).

def add_days(start_dt, days):
    end_dt = start_dt.replace(hour=12, minute=0) + datetime.timedelta(days=days)
    return end_dt.replace(hour=start_dt.hour, minute=start_dt.minute)
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Note, that both of the solutions only work for adding, not for subtracting though. The latter further gives errors as replace expects day, hour and minute instead of days, hours and minutes. – Marcus V. Mar 08 '18 at 19:29
  • @MarcusV. thank you very much for pointing out my typos! I don't understand why you say it only works for adding though, using a negative number for `days` on the second solution works perfectly for me. – Mark Ransom Mar 08 '18 at 20:42
  • Inputs "2017-10-30 00:00:00+01:00" and timedelta(-1) result in "2017-10-29 00:00:00+01:00" and "2017-03-27 00:00:00+02:00" + timedelta(-1) result in "2017-03-26 00:00:00+02:00", which is the correct time, but wrong offset information (this is for CET, where on those days there is DST change). Hence, again normalize() or something like this is still needed, but yesterday night I didn't get it to work. – Marcus V. Mar 09 '18 at 07:54
  • The opposite worked weirdly though: "2017-10-29 00:00:00+02:00" + timedelta(1) results in "2017-10-30 00:00:00+01:00" and "2017-03-26 00:00:00+01:00" results in "2017-03-27 00:00:00+02:00", as expected. – Marcus V. Mar 09 '18 at 07:56
  • @MarcusV. what are you using for a timezone class? – Mark Ransom Mar 09 '18 at 16:47
  • pytz. I added a gist [here](https://gist.github.com/marcus-voss/753a908afd7054442ddf08e8715116d9) – Marcus V. Mar 09 '18 at 19:19