From 7da9f221668f8fa0fcfad6ab8732ce3cbcd1c3fd Mon Sep 17 00:00:00 2001 From: Luke Mino-Altherr Date: Mon, 16 Mar 2026 11:33:21 -0400 Subject: [PATCH] fix: add UTC timezone suffix to datetime serializers Co-authored-by: Amp Amp-Thread-ID: https://ampcode.com/threads/T-019cf73e-7f44-7003-8886-58eaaf1edbf4 --- app/assets/api/schemas_out.py | 20 ++++++++++++++++---- app/assets/helpers.py | 2 +- app/database/models.py | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/assets/api/schemas_out.py b/app/assets/api/schemas_out.py index f36447856..db7efbd4b 100644 --- a/app/assets/api/schemas_out.py +++ b/app/assets/api/schemas_out.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from typing import Any from pydantic import BaseModel, ConfigDict, Field, field_serializer @@ -20,7 +20,11 @@ class AssetSummary(BaseModel): @field_serializer("created_at", "updated_at", "last_access_time") def _serialize_datetime(self, v: datetime | None, _info): - return v.isoformat() if v else None + if v is None: + return None + if v.tzinfo is None: + v = v.replace(tzinfo=timezone.utc) + return v.isoformat() class AssetsList(BaseModel): @@ -41,7 +45,11 @@ class AssetUpdated(BaseModel): @field_serializer("updated_at") def _serialize_updated_at(self, v: datetime | None, _info): - return v.isoformat() if v else None + if v is None: + return None + if v.tzinfo is None: + v = v.replace(tzinfo=timezone.utc) + return v.isoformat() class AssetDetail(BaseModel): @@ -60,7 +68,11 @@ class AssetDetail(BaseModel): @field_serializer("created_at", "last_access_time") def _serialize_datetime(self, v: datetime | None, _info): - return v.isoformat() if v else None + if v is None: + return None + if v.tzinfo is None: + v = v.replace(tzinfo=timezone.utc) + return v.isoformat() class AssetCreated(AssetDetail): diff --git a/app/assets/helpers.py b/app/assets/helpers.py index 3798f3933..4c2b0f681 100644 --- a/app/assets/helpers.py +++ b/app/assets/helpers.py @@ -34,7 +34,7 @@ def escape_sql_like_string(s: str, escape: str = "!") -> tuple[str, str]: def get_utc_now() -> datetime: - """Naive UTC timestamp (no tzinfo). We always treat DB datetimes as UTC.""" + """Naive UTC timestamp (no tzinfo) for DB columns declared with timezone=False.""" return datetime.now(timezone.utc).replace(tzinfo=None) diff --git a/app/database/models.py b/app/database/models.py index e7572677a..aefcfdcf2 100644 --- a/app/database/models.py +++ b/app/database/models.py @@ -1,5 +1,5 @@ from typing import Any -from datetime import datetime +from datetime import datetime, timezone from sqlalchemy.orm import DeclarativeBase class Base(DeclarativeBase): @@ -13,6 +13,8 @@ def to_dict(obj: Any, include_none: bool = False) -> dict[str, Any]: if val is None and not include_none: continue if isinstance(val, datetime): + if val.tzinfo is None: + val = val.replace(tzinfo=timezone.utc) out[field] = val.isoformat() else: out[field] = val