ZhuLinsen/daily_stock_analysis · error · ValueError
unknown timezone: {raw}
Error message
unknown timezone: {raw} What it means
ValueError from validate_notification_timezone when ZoneInfo(raw) raises ZoneInfoNotFoundError — the supplied NOTIFICATION_TIMEZONE string is not a resolvable IANA timezone identifier. The name must exist in the system tzdata (e.g. Asia/Shanghai, America/New_York); abbreviations and made-up names fail.
Source
Thrown at src/notification_noise.py:122
match = _QUIET_HOURS_RE.match(raw)
if not match:
raise ValueError("NOTIFICATION_QUIET_HOURS must be in HH:MM-HH:MM format")
start_hour, start_minute, end_hour, end_minute = [int(group) for group in match.groups()]
return start_hour * 60 + start_minute, end_hour * 60 + end_minute
def validate_notification_timezone(value: Optional[str]) -> None:
"""Validate an optional IANA timezone name."""
raw = str(value or "").strip()
if not raw:
return
if ZoneInfo is None:
raise ValueError("zoneinfo is unavailable")
try:
ZoneInfo(raw)
except ZoneInfoNotFoundError as exc:
raise ValueError(f"unknown timezone: {raw}") from exc
def is_time_in_quiet_hours(now: datetime, quiet_hours: Tuple[int, int]) -> bool:
"""Return whether *now* falls inside a quiet-hours interval."""
start_minute, end_minute = quiet_hours
minute_of_day = now.hour * 60 + now.minute
if start_minute == end_minute:
return False
if start_minute < end_minute:
return start_minute <= minute_of_day < end_minute
return minute_of_day >= start_minute or minute_of_day < end_minute
def _resolve_now(timezone_name: Optional[str], now: Optional[datetime]) -> datetime:
raw_timezone = str(timezone_name or "").strip()
if raw_timezone:
if ZoneInfo is None:View on GitHub (pinned to 5159bd72e8)
Solutions
- Use the exact IANA identifier, e.g. NOTIFICATION_TIMEZONE=Asia/Shanghai
- Fix typos and case — identifiers are case-sensitive (Europe/London, not europe/london)
- In minimal containers install the tzdata package (apk add tzdata / apt-get install tzdata) or add the Python tzdata package so valid names resolve
- Verify quickly with python -c "from zoneinfo import ZoneInfo; ZoneInfo('Asia/Shanghai')"
Example fix
# before NOTIFICATION_TIMEZONE=CST # after NOTIFICATION_TIMEZONE=Asia/Shanghai
Defensive patterns
Strategy: validation
Validate before calling
try:
from zoneinfo import ZoneInfo
except ImportError:
ZoneInfo = None
def is_known_timezone(name: str) -> bool:
if ZoneInfo is None:
return False
try:
ZoneInfo(name.strip())
return True
except Exception:
return False Try / catch
try:
validate_notification_timezone(os.getenv("NOTIFICATION_TIMEZONE"))
except ValueError as exc:
log.error("Bad NOTIFICATION_TIMEZONE: %s — use IANA names like Asia/Shanghai", exc)
raise Prevention
- Offer timezone names from a known IANA list in UI/config, not free text
- Install tzdata in slim Docker images
- Smoke-test the configured timezone at container startup
When it happens
Trigger: Setting NOTIFICATION_TIMEZONE to values like 'CST', 'GMT+8', 'Beijing', 'utc+8', or 'Asia/Shangahi' (typo). Only exact IANA keys from the tz database resolve.
Common situations: Using a timezone abbreviation instead of the IANA name; typos in city/region keys; a slim Docker image without the tzdata package installed so even valid names fail; case mismatches.
Related errors
- NOTIFICATION_QUIET_HOURS must be in HH:MM-HH:MM format
- validation_failed
- capability_unsupported
- Responses API surface requires a normalized openai/<model> r
- LLM route aliases cannot mix API surfaces: {sorted(surface_c
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/c70a0cfad1b2542e.
Report an issue: GitHub.