fix(forecast): semaines calées sur le référentiel UTC du journal

Les horodatages board_events sont en UTC (SQLite): une fermeture
en soirée locale tombait hors des semaines locales et faussait
le débit hebdomadaire.
This commit is contained in:
Spark
2026-10-11 20:15:23 -04:00
parent 2fde103e93
commit 58204e621e
+11 -3
View File
@@ -7,7 +7,15 @@ date, and are withheld entirely when the journal has no closures
to learn from — "not enough history" is an answer, too.
"""
from datetime import date, datetime, timedelta
from datetime import date, datetime, timedelta, timezone
def _journal_today() -> date:
"""'Today' in the journal's frame: board_events stamps are UTC
(SQLite datetime('now')), so week buckets anchor to UTC —
otherwise closures logged in the local evening (already
tomorrow in UTC) fall outside every bucket."""
return datetime.now(timezone.utc).date()
MONTHS_FR = [
"janvier", "février", "mars", "avril", "mai", "juin",
@@ -35,7 +43,7 @@ def _event_date(event: dict) -> date | None:
def weekly_closures(events: list[dict], weeks: int = 8,
today: date | None = None) -> list[dict]:
"""Closure counts per ISO week, oldest first, current week last."""
today = today or date.today()
today = today or _journal_today()
current_monday = today - timedelta(days=today.weekday())
buckets: list[dict] = []
for i in range(weeks - 1, -1, -1):
@@ -83,7 +91,7 @@ def estimate(remaining: int, weekly: list[dict],
no throughput to project from, else dates: central (avg rate),
earliest (best week), latest (worst nonzero week, if any).
"""
today = today or date.today()
today = today or _journal_today()
if remaining <= 0:
return {"done": True}
stats = throughput_stats(weekly)