SAFETY-123: the day plan's hour loop steps in UTC and always ends
dayplan._hour_slices() added an hour to the local wall clock and read it back. Without tzdata (tariff._EUTimezone) 02:00 on the spring change reads as 00:00 UTC again, so the loop never advanced and the list grew until the process died. Each step now adds the time left in the local hour to the UTC instant. Ordinary days give the old slices; the spring day gives 23 slices and the autumn day 25. No option, no text change. test_safety123.py: every quarter of 27-29 March and 30 Oct-1 Nov 2027 (and the US change days) for the slices, dayplan.plan() and Controller._mode_roles(), each call under a hard time limit. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
co-authored by
Claude
parent
a1d07030f8
commit
d2820e8b9b
@@ -157,13 +157,15 @@ class Plan:
|
||||
|
||||
|
||||
def _hour_slices(t0, t1):
|
||||
"""Local-hour slices of [t0, t1): (start, end, local hour)."""
|
||||
"""Local-hour slices of [t0, t1): (start, end, local hour).
|
||||
|
||||
Steps in UTC, so `t` always advances (SAFETY-123, DECISIONS)."""
|
||||
out, t = [], t0
|
||||
while t < t1:
|
||||
lt = _local(t)
|
||||
nxt = (lt.replace(minute=0, second=0, microsecond=0)
|
||||
+ timedelta(hours=1)).astimezone(timezone.utc)
|
||||
e = min(nxt, t1)
|
||||
left = timedelta(minutes=60 - lt.minute) - timedelta(
|
||||
seconds=lt.second, microseconds=lt.microsecond)
|
||||
e = min(t.astimezone(timezone.utc) + left, t1)
|
||||
out.append((t, e, lt.hour))
|
||||
t = e
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user