"""Timezone helpers for web UI.""" from contextvars import ContextVar from datetime import datetime from typing import Optional from zoneinfo import ZoneInfo, ZoneInfoNotFoundError _current_timezone: ContextVar[str] = ContextVar("current_timezone", default="UTC") def set_current_timezone(tz: str) -> None: _current_timezone.set(tz) def get_current_timezone() -> str: return _current_timezone.get() def get_common_timezones() -> list[str]: """Return a curated list of common IANA timezones for the UI.""" return [ "UTC", "Europe/Moscow", "Europe/Samara", "Asia/Krasnoyarsk", "Asia/Novosibirsk", "Asia/Irkutsk", "Asia/Yakutsk", "Asia/Vladivostok", "Asia/Kamchatka", "Asia/Almaty", "Asia/Tashkent", "Asia/Tbilisi", ] def _ensure_aware(dt: datetime, default_tz: str = "UTC") -> datetime: if dt.tzinfo is None: return dt.replace(tzinfo=ZoneInfo(default_tz)) return dt def localtime( value: Optional[datetime], tz: Optional[str] = None, fmt: str = "%Y-%m-%d %H:%M", ) -> str: """Convert a UTC datetime to the configured timezone and format it.""" if value is None: return "-" tz_name = tz or get_current_timezone() try: zone = ZoneInfo(tz_name) except ZoneInfoNotFoundError: zone = ZoneInfo("UTC") dt = _ensure_aware(value) return dt.astimezone(zone).strftime(fmt) def localtime_iso(value: Optional[datetime], tz: Optional[str] = None) -> str: """Convert a UTC datetime to the configured timezone and return ISO string.""" if value is None: return "" tz_name = tz or get_current_timezone() try: zone = ZoneInfo(tz_name) except ZoneInfoNotFoundError: zone = ZoneInfo("UTC") dt = _ensure_aware(value) return dt.astimezone(zone).isoformat()