Files
video-gen/video-gen-api/app/services/credit/time_policy.py
T
2026-08-11 09:24:18 +08:00

40 lines
1.3 KiB
Python

from __future__ import annotations
import calendar
from datetime import datetime, time, timedelta
from zoneinfo import ZoneInfo
from app.services.credit.utils import ensure_aware
BUSINESS_TZ = ZoneInfo("Asia/Shanghai")
def to_business_time(value: datetime) -> datetime:
return ensure_aware(value).astimezone(BUSINESS_TZ)
def add_natural_months(anchor_at: datetime, months: int) -> datetime:
"""始终基于传入锚点计算自然月,月底压缩后下月恢复原锚点日。"""
anchor = to_business_time(anchor_at)
month_index = anchor.year * 12 + anchor.month - 1 + int(months)
year, month_zero = divmod(month_index, 12)
month = month_zero + 1
target_day = min(anchor.day, calendar.monthrange(year, month)[1])
return anchor.replace(year=year, month=month, day=target_day)
def natural_month_period(anchor_at: datetime, sequence: int) -> tuple[datetime, datetime]:
start = add_natural_months(anchor_at, sequence)
end = add_natural_months(anchor_at, sequence + 1)
return start, end
def next_local_midnight(value: datetime) -> datetime:
local = to_business_time(value)
next_day = local.date() + timedelta(days=1)
return datetime.combine(next_day, time.min, tzinfo=BUSINESS_TZ)
def last_usable_at(expires_at: datetime) -> datetime:
return ensure_aware(expires_at) - timedelta(microseconds=1)