Verified Commit 99557b65 authored by Jakob Moser's avatar Jakob Moser
Browse files

Add UtcDateTime type

parent 7990beef
Loading
Loading
Loading
Loading
+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