"""tz-aware/naive datetime 경계 정규화 헬퍼. stock_bans / stock_bans_v2 등 일부 테이블의 DateTime 컬럼은 tz-naive인 반면, `loss_tracker.record_trade_result()`가 만드는 ban_until은 tz-aware(UTC)이다. asyncpg는 offset-naive/aware 혼용 시 DataError(저장)·TypeError(비교)를 던지므로, DB 경계(저장 직전/로드 직후)에서 반드시 이 헬퍼로 정규화한다. """ from datetime import datetime, timezone from typing import Optional def to_naive_utc(dt: Optional[datetime]) -> Optional[datetime]: """DB 저장 직전 정규화: tz-aware → UTC 변환 후 tzinfo 제거. naive는 그대로 반환.""" if dt is None: return None if dt.tzinfo is not None: return dt.astimezone(timezone.utc).replace(tzinfo=None) return dt def to_aware_utc(dt: Optional[datetime]) -> Optional[datetime]: """DB에서 읽은 직후 정규화: tz-naive → UTC로 간주해 tzinfo 부착. aware는 그대로 반환.""" if dt is None: return None if dt.tzinfo is None: return dt.replace(tzinfo=timezone.utc) return dt.astimezone(timezone.utc)