
Stuart Bishop <stuart@stuartbishop.net> writes: ...
the complexities and slowdowns of timeline arithmetic. While not changing the behaviour of datetime at all, we could get cats and dogs living together by just clarifying what it actually is.
An *observation*: the local timezone -- the only timezone with a variable utc offset in _stdlib -- behaves like pytz_: # start with the same utc time utc_time = datetime(2015, 10, 25, 1, tzinfo=timezone.utc) stdlib_time = utc_time.astimezone() # stdlib local time pytz_time = utc_time.astimezone(tzlocal.get_localzone()) dateutil_time = utc_time.astimezone(dateutil.tz.tzlocal()) All times are consistent so far. Perform the same operations:
stdlib_time - timedelta(seconds=1) datetime.datetime(2015, 10, 25, 1, 59, 59, tzinfo=datetime.timezone(datetime.timedelta(0, 3600), 'CET')) pytz_time - timedelta(seconds=1) datetime.datetime(2015, 10, 25, 1, 59, 59, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>) dateutil_time - timedelta(seconds=1) datetime.datetime(2015, 10, 25, 1, 59, 59, tzinfo=tzlocal())
Get different results. The times are the same but utc offset are different:
(stdlib_time - timedelta(seconds=1)).utcoffset() datetime.timedelta(0, 3600) (pytz_time - timedelta(seconds=1)).utcoffset() datetime.timedelta(0, 3600) (dateutil_time - timedelta(seconds=1)).utcoffset() #XXX different datetime.timedelta(0, 7200)
It is expected for arithmetic in the presense of DST transitions. Here's the standard fix:
(stdlib_time - timedelta(seconds=1)).astimezone() datetime.datetime(2015, 10, 25, 2, 59, 59, tzinfo=datetime.timezone(datetime.timedelta(0, 7200), 'CEST')) (pytz_time - timedelta(seconds=1)).astimezone(tzlocal.get_localzone()) datetime.datetime(2015, 10, 25, 2, 59, 59, tzinfo=<DstTzInfo 'Europe/Paris' CEST+2:00:00 DST>) (dateutil_time - timedelta(seconds=1)).astimezone(dateutil.tz.tzlocal()) #XXX different datetime.datetime(2015, 10, 25, 1, 59, 59, tzinfo=tzlocal()) datetime(2015, 10, 25, 1, 59, 59, tzinfo=dateutil.tz.tzlocal()).strftime('%Z%z') 'CEST+0200'
Now the all timezones are the same but the times are different. pytz recommends normalize() method instead of astimezone() here:
tzlocal.get_localzone().normalize(pytz_time - timedelta(seconds=1)) datetime.datetime(2015, 10, 25, 2, 59, 59, tzinfo=<DstTzInfo 'Europe/Paris' CEST+2:00:00 DST>)
The result is the same in this case. It is a _fact_. It is how python behaves now on my platform. To try it yourself, add this at the top: import os import time from datetime import datetime, timezone, timedelta os.environ['TZ'] = 'Europe/Paris' time.tzset() import dateutil.tz import tzlocal # get local timezone as pytz tzinfo