Skip to content

Commit f628094

Browse files
fix: consistent UTC timestamp handling for PostgreSQL in DatabaseSessionService
Fixes two timestamp inconsistencies that cause stale session detection failures when using PostgreSQL with asyncpg: 1. append_event() now strips timezone info for PostgreSQL (matching create_session() behavior). Previously, PostgreSQL got a local-time naive datetime via datetime.fromtimestamp(), while create_session() stored a UTC-based naive datetime. This mismatch caused get_update_timestamp() to return incorrect values when the server timezone differs from UTC. 2. get_update_timestamp() now uses tzinfo-awareness to decide whether to interpret a naive datetime as UTC, rather than checking only for SQLite. This correctly handles both SQLite and PostgreSQL naive datetimes without requiring callers to pass dialect flags. Fixes #4366 Related: #1848 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4b677e7 commit f628094

File tree

2 files changed

+15
-12
lines changed

2 files changed

+15
-12
lines changed

src/google/adk/sessions/database_session_service.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,12 +683,12 @@ async def append_event(self, session: Session, event: Event) -> Event:
683683
storage_session.state | state_deltas["session"]
684684
)
685685

686-
if is_sqlite:
687-
update_time = datetime.fromtimestamp(
688-
event.timestamp, timezone.utc
689-
).replace(tzinfo=None)
690-
else:
691-
update_time = datetime.fromtimestamp(event.timestamp)
686+
# Convert event timestamp to a UTC datetime. SQLite and PostgreSQL
687+
# use TIMESTAMP WITHOUT TIME ZONE, so the tzinfo must be stripped to
688+
# avoid asyncpg DataError / SQLite comparison issues.
689+
update_time = datetime.fromtimestamp(event.timestamp, timezone.utc)
690+
if is_sqlite or self.db_engine.dialect.name == _POSTGRESQL_DIALECT:
691+
update_time = update_time.replace(tzinfo=None)
692692
storage_session.update_time = update_time
693693
sql_session.add(schema.StorageEvent.from_event(session, event))
694694

src/google/adk/sessions/schemas/v1.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,15 @@ def update_timestamp_tz(self) -> float:
119119
)
120120
return self.get_update_timestamp(is_sqlite=is_sqlite)
121121

122-
def get_update_timestamp(self, is_sqlite: bool) -> float:
123-
"""Returns the time zone aware update timestamp."""
124-
if is_sqlite:
125-
# SQLite does not support timezone. SQLAlchemy returns a naive datetime
126-
# object without timezone information. We need to convert it to UTC
127-
# manually.
122+
def get_update_timestamp(self, is_sqlite: bool = False) -> float:
123+
"""Returns the update timestamp as a POSIX float.
124+
125+
Naive datetimes (returned by SQLite and PostgreSQL which use
126+
``TIMESTAMP WITHOUT TIME ZONE``) are interpreted as UTC. Timezone-aware
127+
datetimes (MySQL, MariaDB) are used directly.
128+
"""
129+
if self.update_time.tzinfo is None:
130+
# Naive datetimes from SQLite / PostgreSQL are stored as UTC.
128131
return self.update_time.replace(tzinfo=timezone.utc).timestamp()
129132
return self.update_time.timestamp()
130133

0 commit comments

Comments
 (0)