from datetime import datetime, timezone from typing import Optional from sqlalchemy import DateTime from sqlalchemy.types import TypeDecorator class ForceTimezoneDateTime(TypeDecorator): """ Store timezone aware timestamps as timezone naive UTC https://docs.sqlalchemy.org/en/20/core/custom_types.html#store-timezone-aware-timestamps-as-timezone-naive-utc """ impl = DateTime cache_ok = True def process_bind_param(self, value: Optional[datetime], dialect): if value is not None: if not value.tzinfo or value.tzinfo.utcoffset(value) is None: raise TypeError("datetime tzinfo is required") value = value.astimezone(timezone.utc).replace(tzinfo=None) return value def process_result_value(self, value: Optional[datetime], dialect): if value is not None: value = value.replace(tzinfo=timezone.utc) return value