ZhuLinsen/daily_stock_analysis · error · ValueError
zoneinfo is unavailable
Error message
zoneinfo is unavailable
What it means
ValueError from validate_notification_timezone when a NOTIFICATION_TIMEZONE value is supplied but the ZoneInfo class could not be imported in the running interpreter. This is an environment capability failure, not a bad timezone name: the code guards the import and only raises here when a timezone is actually requested while zoneinfo is unavailable.
Source
Thrown at src/notification_noise.py:118
raw = str(value or "").strip()
if not raw:
return None
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
View on GitHub (pinned to 5159bd72e8)
Solutions
- Upgrade the runtime to Python 3.9 or newer where zoneinfo is in the standard library
- Leave NOTIFICATION_TIMEZONE empty/unset — quiet hours then use local time and the import is never required
- On custom builds, ensure the stdlib zoneinfo module and tzdata are included in the image
- Pin CI/deploy images to python:3.10+ or equivalent
Example fix
# before (python 3.8 runtime, timezone set) NOTIFICATION_TIMEZONE=Asia/Shanghai # after # either run on Python >= 3.9, or unset: # NOTIFICATION_TIMEZONE=
Defensive patterns
Strategy: validation
Validate before calling
import sys
def zoneinfo_available() -> bool:
if sys.version_info < (3, 9):
return False
try:
from zoneinfo import ZoneInfo # noqa: F401
return True
except ImportError:
return False Try / catch
try:
validate_notification_timezone(tz)
except ValueError as exc:
if str(exc) == "zoneinfo is unavailable":
log.warning("Timezone ignored: needs Python >= 3.9; continuing with local time")
else:
raise Prevention
- Assert Python >= 3.9 in deployment metadata when timezone config is used
- Include stdlib zoneinfo (and tzdata fallback package) in minimal container images
- Skip timezone validation instead of crashing when the feature is optional
When it happens
Trigger: Running on Python older than 3.9 (zoneinfo added in 3.9) with NOTIFICATION_TIMEZONE set to a non-empty value, or on a stripped interpreter where the stdlib zoneinfo module was removed. Any non-empty timezone config triggers it.
Common situations: Deploying to a legacy Python 3.8 image; a minimal/alpine-like custom build pruning stdlib modules; a virtualenv built against an old system Python; CI matrix still including EOL Python versions.
Related errors
- unknown timezone: {raw}
- share_image_unavailable
- pytdx 库未安装
- 加载 Futu OpenAPI SDK 失败: {exc}
- FUTU_OPEND_PORT 不是有效端口: {raw_port!r}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/72333746f6da50f9.
Report an issue: GitHub.