d87347b032
* Date fix: introduce GOODNEWS_TZ (goodnews/localtime.py) so the brief's "today" rolls over in a pinned zone (Eastern) instead of UTC — robust to host-clock resets. The home page now formats the brief's date in each VISITOR's local timezone (from its UTC freshness stamp), so nobody ever sees "tomorrow." * Admin "Content served": articles live, fresh (7d), ingested (24h), summaries, active sources, today's brief size — queries.content_stats(). * Admin "Source health": per active source, the failure streak, last error, accepted contribution, and computed next-poll time (so backoff / "resting until" is visible), via queries.source_health() reusing the feeds backoff math. Failing sources sort to the top; times render in the viewer's zone. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1.0 KiB
Python
33 lines
1.0 KiB
Python
"""The site's canonical local day.
|
|
|
|
There is one daily brief, so "today" must resolve to a single timezone — not the
|
|
host clock (which is UTC on the server and was silently reset on a rebuild).
|
|
GOODNEWS_TZ pins it explicitly (default UTC) so a rebuild can't reintroduce the
|
|
"brief shows tomorrow's date in the evening" bug. This governs when the brief
|
|
rolls over and the canonical date on the server-rendered /today page; each
|
|
visitor's *displayed* date is formatted in their own browser timezone.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
|
|
|
|
def site_tz() -> ZoneInfo:
|
|
name = os.environ.get("GOODNEWS_TZ", "UTC")
|
|
try:
|
|
return ZoneInfo(name)
|
|
except (ZoneInfoNotFoundError, ValueError):
|
|
return ZoneInfo("UTC")
|
|
|
|
|
|
def local_now() -> datetime:
|
|
return datetime.now(site_tz())
|
|
|
|
|
|
def local_today() -> str:
|
|
"""The site's current calendar date (ISO yyyy-mm-dd) in GOODNEWS_TZ."""
|
|
return local_now().date().isoformat()
|