Problem
Python's datetime.strptime and date.fromisoformat handle dates differently across Python versions, and the comparison with datetime.now() uses local time — so a test disabled until "2026-04-01" re-enables at different wall-clock moments depending on the runner's timezone. In Sydney it re-enables 11 hours earlier than in London.
Additionally, non-padded formats like "2026-4-1" silently parse in some contexts but raise in others.
Proposed fix
Replace all date parsing with a strict validator that:
- Enforces
YYYY-MM-DD format with a regex — throws loudly on bad input
- Compares against UTC midnight of the day after the given date
import re
from datetime import timezone, datetime, timedelta
DATE_RE = re.compile(r'^\d{4}-\d{2}-\d{2}$')
def parse_disabled_until(raw: str | None, row_num: int) -> datetime | None:
if not raw or not raw.strip():
return None
if not DATE_RE.match(raw.strip()):
raise ValueError(
f"[skipper] Row {row_num}: invalid disabledUntil '{raw}'. Use YYYY-MM-DD."
)
# Parse as UTC midnight of the day AFTER — disabled through end of that calendar day UTC
d = datetime.strptime(raw.strip(), "%Y-%m-%d").replace(tzinfo=timezone.utc)
return d + timedelta(days=1)
def is_disabled(row: dict, row_num: int) -> bool:
until = parse_disabled_until(row.get("disabledUntil"), row_num)
return until is not None and datetime.now(timezone.utc) < until
Acceptance criteria
Effort estimate
~8 lines in the core resolver. No architecture changes required.
Problem
Python's
datetime.strptimeanddate.fromisoformathandle dates differently across Python versions, and the comparison withdatetime.now()uses local time — so a test disabled until"2026-04-01"re-enables at different wall-clock moments depending on the runner's timezone. In Sydney it re-enables 11 hours earlier than in London.Additionally, non-padded formats like
"2026-4-1"silently parse in some contexts but raise in others.Proposed fix
Replace all date parsing with a strict validator that:
YYYY-MM-DDformat with a regex — throws loudly on bad inputAcceptance criteria
"2026-4-1") raise a descriptive error with the row number"2026-04-01"is consistently treated as UTC midnight, regardless of runner timezone2026-04-01stays disabled until2026-04-02T00:00:00ZEffort estimate
~8 lines in the core resolver. No architecture changes required.