parse: fix time zone handling in scheduler time parsing #2515
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
Users reported that
run_daily()and other scheduler functions were scheduling callbacks at incorrect times, sometimes with unexpected offsets from the expected time. This regression was introduced after v4.4.2.Example from issue:
Expected execution:
08:00:00Actual execution:
09:07:00What Caused the Regression
In v4.4.2, the code correctly handled pytz timezones:
The
convert_naive()method properly usedself.AD.tz.localize(dt), which is the required pattern for pytz timezones to correctly determine the UTC offset based on DST for that specific date.When the time parsing was refactored into
parse.py, this pattern was replaced with:This is incorrect for pytz timezones. Unlike standard
tzinfoimplementations, pytz timezones are stateful and require thelocalize()method to properly determine the UTC offset. When you pass a pytz timezone directly todatetime.combine()or usedt.replace(tzinfo=...), pytz may apply an incorrect default offset that doesn't account for DST on that specific date.Solution
Instead of reverting to the old
localize()pattern (which is pytz-specific and non-standard), we normalize pytz timezones toZoneInfo(PEP 615) at the boundary:normalize_tz(tz)- Converts pytz timezones to their equivalentZoneInfousing the IANA zone name. ZoneInfo behaves like a standardtzinfoand handles DST correctly with normalreplace(tzinfo=...)calls.localize_naive(naive_dt, tz)- A helper that normalizes the timezone first, then uses standardreplace(tzinfo=...).This approach:
Fixes #2338
Fixes #2388
Fixes #2391
Fixes #2393
Fixes #2400