Files
2026-07-06 20:48:03 +08:00

56 lines
1.6 KiB
Python

"""统一时间工具:所有对外展示时间按当前时区输出。"""
from __future__ import annotations
import os
from datetime import datetime, time, timedelta
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
def get_timezone_name() -> str:
return os.getenv("TZ") or os.getenv("APP_TIMEZONE") or "Asia/Shanghai"
def get_timezone() -> ZoneInfo:
name = get_timezone_name()
try:
return ZoneInfo(name)
except ZoneInfoNotFoundError:
return ZoneInfo("Asia/Shanghai")
APP_TZ = get_timezone()
def now_tz() -> datetime:
"""当前应用时区时间。"""
return datetime.now(APP_TZ)
def to_app_tz(value: datetime) -> datetime:
"""把 datetime 转为应用时区;无 tzinfo 的值按应用时区本地时间处理。"""
if value.tzinfo is None:
return value.replace(tzinfo=APP_TZ)
return value.astimezone(APP_TZ)
def format_dt(value: datetime | None) -> str | None:
"""面向 API/前端的统一时间格式,包含时区偏移。"""
if value is None:
return None
return to_app_tz(value).isoformat(sep=" ", timespec="seconds")
def from_timestamp(ts: float) -> datetime:
return datetime.fromtimestamp(ts, APP_TZ)
def local_day_range(day: str | None = None) -> tuple[str, datetime, datetime]:
"""返回本地日范围。为了兼容当前 ORM/数据库字段,过滤条件返回 naive datetime。"""
if day:
target = datetime.strptime(day, "%Y-%m-%d").date()
else:
target = now_tz().date()
start = datetime.combine(target, time.min)
end = start + timedelta(days=1)
return target.strftime("%Y-%m-%d"), start, end