1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
# ruff: noqa: FA100
import datetime
from typing import Optional
from sqlalchemy import DateTime
from sqlalchemy.engine import Dialect
from sqlalchemy.types import TypeDecorator
__all__ = ("DateTimeUTC",)
class DateTimeUTC(TypeDecorator[datetime.datetime]):
"""Timezone Aware DateTime.
Ensure UTC is stored in the database and that TZ aware dates are returned for all dialects.
"""
impl = DateTime(timezone=True)
cache_ok = True
@property
def python_type(self) -> type[datetime.datetime]:
return datetime.datetime
def process_bind_param(self, value: Optional[datetime.datetime], dialect: Dialect) -> Optional[datetime.datetime]:
if value is None:
return value
if not value.tzinfo:
msg = "tzinfo is required"
raise TypeError(msg)
return value.astimezone(datetime.timezone.utc)
def process_result_value(self, value: Optional[datetime.datetime], dialect: Dialect) -> Optional[datetime.datetime]:
if value is None:
return value
if value.tzinfo is None:
return value.replace(tzinfo=datetime.timezone.utc)
return value
|