-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
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:
- We create a session at 2025-07-09 9:30 PDT
- Mysql server store it as 2025-07-09 16:30 UTC
- 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:
- Start the mysql server which has a UTC timezone (or any other timezone different from your local timezone)
- Call DatabaseSessionService to create a new session at time T1
- Call DatabaseSessionService to get the created session and check its lastUpdateTime which is T2
- 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).
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.