66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
"""Время для БД и API: колонки DateTime в проекте — naive; договорённость — UTC."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from datetime import date, datetime, timezone
|
||
from typing import Union
|
||
from zoneinfo import ZoneInfo
|
||
|
||
_DEFAULT_DISPLAY_TZ = "Europe/Moscow"
|
||
|
||
|
||
def zoneinfo_or_utc(name: str) -> Union[ZoneInfo, timezone]:
|
||
"""IANA timezone; on Windows without tzdata falls back to UTC for «UTC»."""
|
||
key = (name or "").strip()
|
||
if not key or key.upper() in {"UTC", "ETC/UTC", "GMT"}:
|
||
return timezone.utc
|
||
try:
|
||
return ZoneInfo(key)
|
||
except Exception:
|
||
if key.upper() in {"UTC", "ETC/UTC", "GMT"}:
|
||
return timezone.utc
|
||
raise
|
||
|
||
|
||
def utc_now_naive() -> datetime:
|
||
"""Текущий момент в UTC без tzinfo (как DateTime в SQLite/SQLAlchemy здесь)."""
|
||
return datetime.now(timezone.utc).replace(tzinfo=None)
|
||
|
||
|
||
def utc_now_iso() -> str:
|
||
"""ISO 8601 с явным UTC (+00:00) для JSON и логов."""
|
||
return datetime.now(timezone.utc).isoformat()
|
||
|
||
|
||
def naive_utc_to_iso(dt: datetime | None) -> str:
|
||
"""Сериализация naive UTC из БД в ISO с суффиксом +00:00."""
|
||
if dt is None:
|
||
return utc_now_iso()
|
||
if dt.tzinfo is not None:
|
||
return dt.astimezone(timezone.utc).isoformat()
|
||
return dt.replace(tzinfo=timezone.utc).isoformat()
|
||
|
||
|
||
def display_timezone_name() -> str:
|
||
"""IANA-имя зоны для календаря/«сегодня» в UI (из конфига приложения)."""
|
||
try:
|
||
from flask import current_app, has_request_context
|
||
|
||
if has_request_context():
|
||
name = current_app.config.get("WESP_DISPLAY_TIMEZONE")
|
||
if name:
|
||
return str(name)
|
||
except Exception:
|
||
pass
|
||
return _DEFAULT_DISPLAY_TZ
|
||
|
||
|
||
def display_calendar_today() -> date:
|
||
"""Сегодняшняя дата в зоне WESP_DISPLAY_TIMEZONE (для диапазонов графиков и т.п.)."""
|
||
tz_name = display_timezone_name()
|
||
try:
|
||
tz = zoneinfo_or_utc(tz_name)
|
||
return datetime.now(tz).date()
|
||
except Exception:
|
||
return datetime.now(timezone.utc).date()
|