"""UTC 时间工具。账本、心跳和授权窗口全部使用 UTC。""" from __future__ import annotations import calendar from datetime import date, datetime, time, timedelta, timezone def utcnow() -> datetime: return datetime.now(timezone.utc) def day_bounds(value: date) -> tuple[datetime, datetime]: """返回某个 UTC 日期的左闭右开区间。""" start = datetime.combine(value, time.min, tzinfo=timezone.utc) return start, start + timedelta(days=1) def add_months(value: datetime, months: int) -> datetime: """按日历月平移,月末日期自动收敛到目标月最后一天。""" if value.tzinfo is None: value = value.replace(tzinfo=timezone.utc) month_index = value.month - 1 + months year = value.year + month_index // 12 month = month_index % 12 + 1 day = min(value.day, calendar.monthrange(year, month)[1]) return value.replace(year=year, month=month, day=day)