from datetime import datetime, timezone, timedelta from typing import Annotated from pydantic import BaseModel, BeforeValidator CST = timezone(timedelta(hours=8)) def _strip_tz(v: datetime | str | None) -> datetime | None: if v is None: return None try: dt = v if isinstance(v, datetime) else datetime.fromisoformat(str(v)) if dt.tzinfo is not None: if dt.tzinfo.utcoffset(None) == timedelta(0): dt = dt.astimezone(CST) return dt.replace(tzinfo=None) return dt except (ValueError, TypeError): return v if isinstance(v, datetime) else None NaiveDatetime = Annotated[datetime, BeforeValidator(_strip_tz)] NaiveDatetimeOptional = Annotated[datetime | None, BeforeValidator(_strip_tz)] class ErrorResponse(BaseModel): detail: str class PaginationParams(BaseModel): page: int = 1 page_size: int = 20 class PaginatedResponse(BaseModel): total: int page: int page_size: int items: list