Question: I am currently attempting to migrate a code base from using pytz to using Python's zoneinfo library. I've run into an issue with how zoneinfo handles daylight saving time transitions when compared to how pytz handles them. Suppose I have a naive datetime object: >>> import datetime >>> start = datetime.datetime(2021, 10, 30, 23, 0)  The approach used for making this object timezone-aware using pytz was to use localize, as follows: >>> local_timezone = pytz.timezone('Europe/Copenhagen') >>> start_cet = local_timezone.localize(start) >>> start_cet datetime.datetime(2021, 10, 30, 23, 0, tzinfo=<DstTzInfo 'Europe/Copenhagen' CEST+2:00:00 DST>)  Notice that start_cet is very close to the end of CEST 2021. If I add, say, 5 hours onto this time, I get the following: >>> end = start_cet + datetime.timedelta(hours=5) >>> end datetime.datetime(2021, 10, 31, 4, 0, tzinfo=<DstTzInfo 'Europe/Copenhagen' CEST+2:00:00 DST>)  Now, in reality, adding 5 hours on to start_cet should in fact land us on 3:00 on 2021/10/31, since leaving DST takes us back one hour, moving from CEST to CET. We can get the correct value by applying astimezone with our pytz timezone: >>> end.astimezone(local_timezone) datetime.datetime(2021, 10, 31, 3, 0, tzinfo=<DstTzInfo 'Europe/Copenhagen' CET+1:00:00 STD>)  Question: What is the equivalent method of finding the actual time when moving through DST when using zoneinfo? Here's what I've tried. zoneinfo has no localize method, instead we are recommended to simply use replace: >>> local_timezone = zoneinfo.ZoneInfo('Europe/Copenhagen') >>> start_cet = start.replace(tzinfo=local_timezone) >>> start_cet datetime.datetime(2021, 10, 30, 23, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Europe/Copenhagen')) >>> start_cet.utcoffset() datetime.timedelta(seconds=7200)  zoneinfo has the benefit over pytz that adding a timedelta will successfully transition us into the correct timezone (as can be seen by the utcoffset result: >>> end = start_cet + datetime.timedelta(hours=5) >>> end datetime.datetime(2021, 10, 31, 4, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Europe/Copenhagen')) >>> end.utcoffset() datetime.timedelta(seconds=3600)  Despite this, with zoneinfo timezones there seems to be no way to get what the actual time would have been when adding 5 hours onto start_cet. As shown above, with pytz I can use astimezone, but with zoneinfo, this does not change anything: >>> end.astimezone(tz=local_timezone) datetime.datetime(2021, 10, 31, 4, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Europe/Copenhagen')) 

Answer: In addition to @deceze's comment (CET specifies a UTC offset, not a time zone), note that timedelta arithmetic in Python is wall time arithmetic. from datetime import datetime, timedelta from zoneinfo import ZoneInfo eu_berlin_tz = ZoneInfo("Europe/Berlin") start = datetime(2021, 10, 30, 23, 0, tzinfo=eu_berlin_tz) dur = timedelta(hours=5) print(start) # 2021-10-30 23:00:00+02:00 => CEST print(start + dur) # 2021-10-31 04:00:00+01:00 => CET  2021-10-30T23:00:00+02:00 to 2021-10-31T04:00:00+01:00 is 5 hours on a wall clock, although a duration of 6 hours passed in reality due to DST becoming inactive. If you add the duration in UTC and then convert back to the specified time zone, the result is more what you expect IIUC: def aware_add(dt, duration): return (dt.astimezone(ZoneInfo("UTC")) + duration).astimezone(dt.tzinfo) print(aware_add(start, dur)) # 2021-10-31 03:00:00+01:00  2021-10-30T23:00:00+02:00 to 2021-10-31T03:00:00+01:00 is 4 hours on the wall clock but 5 hours in reality.