fix(tz): timezone-aware datetimes — unblock TZ=Asia/Jerusalem (#210)
Backend follow-up to INV-UI9 (X6 §"אודיט-נלווה"): make server-side
datetimes explicit so flipping the container to TZ=Asia/Jerusalem cannot
silently skew stored or displayed timestamps. Storage stays UTC; human
display is Israel time.
- audit.py: naive datetime.utcnow() → datetime.now(timezone.utc) for the
TIMESTAMPTZ audit_log.created_at. Under TZ=Asia/Jerusalem the naive UTC
wall-clock would be read as Israel-local and stored ~3h off. (§6: no
silent skew.)
- calibrate_effort.py: _ts() report stamp now Israel-time via
ZoneInfo("Asia/Jerusalem") with a filename-safe "-IL" suffix (script runs
on the UTC host); added a labeled "שעון ישראל" line to the report header
so the chair-facing timestamp is unambiguous. --self-test still ALL PASS.
- research_md.py: display fields made deterministic Israel-tz —
update_chair_position timestamp (datetime.now(IL_TZ)) and parse() mtime
(datetime.fromtimestamp(..., tz=IL_TZ)) — correct regardless of process TZ.
Left intentionally Israel-local-day date.today()/year-cutoff call sites
untouched (drafting/party_claims_summary/block_writer/court_fetch_supreme)
— a Jerusalem committee wants the Israel calendar day; they resolve
correctly once TZ flips.
Invariants: INV-UI9 (store-UTC / display-Israel, server side); §6
(timezone-aware datetimes, no silent ~3h skew).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,8 +58,9 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfo
|
||||
from statistics import mean
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -344,8 +345,17 @@ async def _run(args, ts: str) -> dict:
|
||||
return {"dry_run": False, "grid": grid_summary, "by_block": by_block}
|
||||
|
||||
|
||||
IL_TZ = ZoneInfo("Asia/Jerusalem")
|
||||
|
||||
|
||||
def _ts() -> str:
|
||||
return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
|
||||
"""Filename-safe report stamp in Israel time (INV-UI9: human-facing display).
|
||||
|
||||
This script runs on the host, which is UTC, so a process-clock stamp would
|
||||
mislead the chair. We pin Asia/Jerusalem and suffix ``IL`` (instead of a bare
|
||||
``Z``) so the displayed/filename time is unambiguously Israel-local.
|
||||
"""
|
||||
return datetime.now(IL_TZ).strftime("%Y%m%dT%H%M%S-IL")
|
||||
|
||||
|
||||
def _write_report(result: dict, ts: str) -> tuple[Path, Path]:
|
||||
@@ -356,8 +366,10 @@ def _write_report(result: dict, ts: str) -> tuple[Path, Path]:
|
||||
|
||||
g = result["grid"]
|
||||
n = g["n_finals"]
|
||||
il_now = datetime.now(IL_TZ).strftime("%Y-%m-%d %H:%M")
|
||||
lines = [
|
||||
f"# #208 — כיול model×effort מול הסופיים — {ts}\n",
|
||||
f"> נוצר: {il_now} (שעון ישראל · Asia/Jerusalem)\n",
|
||||
f"> ⚠️ **גודל-מדגם: {n} סופיים** ({', '.join(g['finals']) or '—'}). "
|
||||
"זוהי **עדות-כיוון, לא רגרסיה** — מעט תיקים בעלי סופי-עלוי. "
|
||||
"ההמלצה אדוויזורית; ההכרעה בידי היו\"ר/המפעיל.\n",
|
||||
|
||||
Reference in New Issue
Block a user