Loading portal/model/UtcDateTime.py 0 → 100644 +51 −0 Changes for portal/model/UtcDateTime.py: 51 added lines, 0 removed lines. Original line number Diff line number Diff line from datetime import datetime, timezone from zoneinfo import ZoneInfo from typing import Optional, Any from sqlalchemy.engine import Dialect import sqlalchemy.types as types class UtcDateTime(types.TypeDecorator): """ A ZonedDateTime object (if there were such a thing in Python) with the timezone fixed to UTC. This is a poor man's attempt at implementing an Instant (which is what I actually want to store, but for which there is no Python type) while also staying as close as possible to the types that do exist in Python. In the database, a UtcDateTime is generally stored as an ISO string (e.g. 2023-11-14T11:00+00:00). Further reading on ZonedDateTime: - https://tc39.es/proposal-temporal/docs/#Temporal-ZonedDateTime - https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/time/ZonedDateTime.html """ impl = types.TypeEngine cache_ok = True def load_dialect_impl(self, dialect: Dialect) -> types.TypeEngine[Any]: return types.String(32) def process_bind_param( self, value: datetime, dialect: Dialect ) -> Optional[str | datetime]: if value is None: return None return value.astimezone(timezone.utc).isoformat() def process_result_value( self, value: str | datetime, dialect: Dialect ) -> Optional[datetime]: if value is None: return None result = datetime.fromisoformat(value) assert ( result.tzinfo == timezone.utc ), "tzinfo of returned object is expected to be timezone.utc" return result Loading
portal/model/UtcDateTime.py 0 → 100644 +51 −0 Changes for portal/model/UtcDateTime.py: 51 added lines, 0 removed lines. Original line number Diff line number Diff line from datetime import datetime, timezone from zoneinfo import ZoneInfo from typing import Optional, Any from sqlalchemy.engine import Dialect import sqlalchemy.types as types class UtcDateTime(types.TypeDecorator): """ A ZonedDateTime object (if there were such a thing in Python) with the timezone fixed to UTC. This is a poor man's attempt at implementing an Instant (which is what I actually want to store, but for which there is no Python type) while also staying as close as possible to the types that do exist in Python. In the database, a UtcDateTime is generally stored as an ISO string (e.g. 2023-11-14T11:00+00:00). Further reading on ZonedDateTime: - https://tc39.es/proposal-temporal/docs/#Temporal-ZonedDateTime - https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/time/ZonedDateTime.html """ impl = types.TypeEngine cache_ok = True def load_dialect_impl(self, dialect: Dialect) -> types.TypeEngine[Any]: return types.String(32) def process_bind_param( self, value: datetime, dialect: Dialect ) -> Optional[str | datetime]: if value is None: return None return value.astimezone(timezone.utc).isoformat() def process_result_value( self, value: str | datetime, dialect: Dialect ) -> Optional[datetime]: if value is None: return None result = datetime.fromisoformat(value) assert ( result.tzinfo == timezone.utc ), "tzinfo of returned object is expected to be timezone.utc" return result