Skip to content

Session lastUpdateTime doesn't handle timezone correctly #1848

@xuanyang15

Description

@xuanyang15

Describe the bug
Similar to #1180 (which is for SQLite), for other databases like mysql or postgresql, if the database server is using a different timezone than the adk app server's timezone. The lastUpdateTime we get in adk for a session will have an offset compared to the real time.

For example, if the adk app server's local timezone is PDT (UTC-7) and mysql server's timezone is UTC:

  1. We create a session at 2025-07-09 9:30 PDT
  2. Mysql server store it as 2025-07-09 16:30 UTC
  3. ADK get session will return it as 2025-07-09 17:30 PDT (which is actually 2025-07-08 23:30 UTC)

To Reproduce
Steps to reproduce the behavior:

  1. Start the mysql server which has a UTC timezone (or any other timezone different from your local timezone)
  2. Call DatabaseSessionService to create a new session at time T1
  3. Call DatabaseSessionService to get the created session and check its lastUpdateTime which is T2
  4. You can see T1 and T2 do not equal (i.e. there is an offset equals to timezone difference)

Example code:

import asyncio
from datetime import datetime, timezone

from google.adk.sessions import DatabaseSessionService

APP_NAME = "test_app"
USER_ID = "test_user"

db_url = "mysql+pymysql://root:0@127.0.0.1:3306/test_session"
session_service = DatabaseSessionService(db_url=db_url)


async def main_async():
  now = datetime.now()
  print(
      f"Current local time is {now.timestamp()} ({now}), UTC time is:"
      f" {now.astimezone(timezone.utc)}"
  )

  session = await session_service.create_session(
      app_name=APP_NAME,
      user_id=USER_ID,
  )
  session_id = session.id
  last_update_time = session.last_update_time
  print(
      f"Created new session: {session_id}, with last update time"
      f" {last_update_time} ({datetime.fromtimestamp(last_update_time)})"
  )

  got_session = await session_service.get_session(
      app_name=APP_NAME, user_id=USER_ID, session_id=session.id
  )
  last_update_time = got_session.last_update_time
  print(
      "Got last update time"
      f" {last_update_time} ({datetime.fromtimestamp(last_update_time)}), UTC"
      f" time is: {datetime.fromtimestamp(last_update_time, tz=timezone.utc)}"
  )


if __name__ == "__main__":
  asyncio.run(main_async())

Expected behavior
ADK get session should return the correct lastUpdateTime (e.g. it should be 2025-07-09 9:30 PDT or 2025-07-09 16:30 UTC, NOT 2025-07-09 16:30 PDT or 2025-07-09 23:30 UTC).

Screenshots
Image

Desktop (please complete the following information):
Unrelated

Model Information:
Unrelated

Additional context
The root cause should be that we are using func.now() to set the onupdate time for db, when SQLAlchemy generates the SQL to build the database, it actually translates func.now() into NOW() or CURRENT_TIMESTAMP. The value it returns depends on the database server settings. For example, if the global/default timezone for a db is set to be UTC, the update time will be set to be a UCT time; if the global time zone for a db is set to be a local time zone (e.g. America/Los_Angeles), the update time will be a local time.

We probably should consider use DateTime(timezone=True) instead of DateTime() when defining the schema of the StorageSession, which will make the timestamp timezone aware. Then we can safely convert the timestamp to a UTC time (e.g. dt.astimezone(timezone.utc).timestamp()) for other calculations.

Metadata

Metadata

Assignees

Labels

services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions