Why is zoneinfo shifting DST by 2 hours instead of 1?

45 Views Asked by At

I need to make sure that when a naive datetime is made aware the DST rules are applied correctly. What I find here is just odd to me.

Somehow zoneinfo decides to increment the DST transition for America/New_York by 2 hours instead of one. It is even shifting the time right before DST to EDT by 2 hours.

for DST New York shifts to 3am at 2am

from zoneinfo import ZoneInfo
from datetime import datetime, timedelta


def zmake_timezone_obj(tz):
    return ZoneInfo(tz)

def zconvert_to_timezone(naive_dt, timezone_str):
    tz_obj = zmake_timezone_obj(timezone_str)
    return naive_dt.astimezone(tz_obj)


dst_start = datetime(2022, 3, 13, 2, 1)

zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())

print()
dst_start = datetime(2022, 3, 13, 1, 59)
zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())


Output:

2022-03-13 04:01:00-04:00 EDT # should be: 2022-03-13 03:01:00-04:00 EDT
2022-03-13 05:01:00-04:00 EDT # should be: 2022-03-13 04:01:00-04:00 EDT

2022-03-13 03:59:00-04:00 EDT # should be: 2022-03-13 01:59:00-05:00 EST
2022-03-13 04:59:00-04:00 EDT # should be: 2022-03-13 03:59:00-04:00 EDT

This is using tzdata version 2023.4 and python version 3.11.4.

What is going on here and how can I correct it?

2

There are 2 best solutions below

0
Mark Ransom On BEST ANSWER

The answer is in the documentation for astimezone:

If self is naive, it is presumed to represent time in the system timezone.

Presumably you're running this code in a computer whose native time zone is two hours different than Eastern. This has nothing to do with whether DST is in effect.

Also note that 2:01 is an invalid time for that date, it falls in the gap between 2:00 and 3:00 that doesn't exist. You shouldn't expect any calculations using that time to make any sense.

3
drew On

With zoneinfo, you don't have to use the old-school .astimezone() style of updating time zones like you did with pytz. Instead, you can do the easy .replace(tzinfo=foo) way:

def alt_convert_to_tz(naive_dt: datetime, timezone_str: str) -> datetime:
    return naive_dt.replace(tzinfo=zmake_timezone_obj(timezone_str))

That gives you the results you want:

new = alt_convert_to_tz(dst_start, 'America/New_York')
print(new, new.tzname()) # 2022-03-13 01:59:00-05:00 EST