Search code examples
datetimepython-3.9

python 3.9.1 datetime arithmetic


While trying the new zoneinfo support in python3.9.1, I noticed that time differences of datetime aware objects differ from those produced by pytz as shown by the output of the below program:

import datetime,zoneinfo,pytz
from sys import version_info
print(f'Python{version_info.major}.{version_info.minor}{version_info.micro}'
f' pytz{pytz.__version__}')
Athens=zoneinfo.ZoneInfo('Europe/Athens')
f='%Y-%m-%d %H:%M:%S'
d=[datetime.datetime.strptime('2020-10-25 00:00:00',f),
   datetime.datetime.strptime('2020-10-25 23:59:59',f)]
print('naive   ',d[1]-d[0])
d=[x.astimezone(Athens) for x in d]
print('zoneinfo',d[1]-d[0])
d=[datetime.datetime.strptime('2020-10-25 00:00:00',f),
   datetime.datetime.strptime('2020-10-25 23:59:59',f)]
athens=pytz.timezone('Europe/Athens')
print('pytz as ',d[1].astimezone(athens)-d[0].astimezone(athens))
print('pytz loc',athens.localize(d[1])-athens.localize(d[0]))

Python3.91 pytz2020.4
naive    23:59:59
zoneinfo 23:59:59
pytz as  1 day, 0:59:59
pytz loc 1 day, 0:59:59

It appears that the native timezone supports ignores the fact that 2020-10-25 was the day of changeover from summertime to winter time and therefore that day's duration was 25 hours. What am I missing?


Solution

  • An illustration of my comment; aware datetime with tzinfo set with a ZoneInfo from zoneinfo returns a wall time timedelta. If you do the same with pytz.timezone aware datetime, you get absolute time timedelta.

    from datetime import datetime
    from zoneinfo import ZoneInfo
    import pytz
    from sys import version_info
    
    print(f'Python {version_info.major}.{version_info.minor}{version_info.micro} pytz {pytz.__version__}')
    # Python 3.90 pytz 2020.4
    
    d=[datetime.fromisoformat('2020-10-25 00:00:00'), datetime.fromisoformat('2020-10-25 23:59:59')]
    
    Athens = ZoneInfo('Europe/Athens')
    print('wall time diff, zoneinfo:', d[1].replace(tzinfo=Athens)-d[0].replace(tzinfo=Athens))
    # wall time diff, zoneinfo: 23:59:59
    
    athens = pytz.timezone('Europe/Athens')
    print('absolute time diff, pytz:', athens.localize(d[1])-athens.localize(d[0]))
    # absolute time diff, pytz: 1 day, 0:59:59
    
    # to get absolute time delta with zoneinfo:
    utc = ZoneInfo('UTC')
    print('absolute time diff, zoneinfo:', d[1].replace(tzinfo=Athens).astimezone(utc)
                                          -d[0].replace(tzinfo=Athens).astimezone(utc))
    # absolute time diff, zoneinfo: 1 day, 0:59:59