Skip to content

Render calendar event times in the user's timezone in chat (#4643)#8495

Open
ZachL111 wants to merge 5 commits into
BasedHardware:mainfrom
ZachL111:zach/calendar-chat-timezone
Open

Render calendar event times in the user's timezone in chat (#4643)#8495
ZachL111 wants to merge 5 commits into
BasedHardware:mainfrom
ZachL111:zach/calendar-chat-timezone

Conversation

@ZachL111

@ZachL111 ZachL111 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Completes the #4643 follow-up I flagged in #8483. The agentic chat's calendar tool, get_calendar_events_tool, rendered Google Calendar event Start and End times in raw UTC / the event's own zone (strftime with %Z), not the user's timezone. So when the model answers "when is my meeting," it can read a UTC wall clock as the user's local time and mislabel the time of day, the same class of bug #8483 fixed for action items.

Fix

Render event Start and End in the user's timezone with an explicit label, for example Start: 2026-06-30 15:00:00 America/Los_Angeles instead of a UTC time. Two small helpers do the work:

  • _resolve_display_tz(tz): the user's ZoneInfo and a label, falling back to UTC on a missing or invalid zone.
  • _format_event_dt(dt, display_tz, label): convert a tz-aware event time to the user's zone (a naive value is treated as UTC) and append the label.

get_calendar_events_tool is async, so the user's timezone is read off the event loop via run_blocking(db_executor, get_user_time_zone, uid) before the events are formatted. All-day events (date only, no time) are left unchanged. This only touches the read tool the chat model uses to answer time questions.

Testing

New tests/unit/test_calendar_timezone.py (registered in test.sh): the helpers convert to the user's zone with a label, fall back to UTC for missing/invalid/empty zones, treat a naive time as UTC, and handle a day-boundary crossing (22:00 UTC is 07:00 the next day in Tokyo). Black and the async-blocker lint are clean (the timezone read is offloaded, so the event loop is not blocked).

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files

Confidence score: 3/5

  • In backend/utils/retrieval/tools/calendar_tools.py, the unguarded run_blocking(notification_db.get_user_time_zone) lookup can fail the whole tool path, causing users to get an error instead of calendar events even when fetch succeeds. Add defensive handling/fallback for timezone lookup (and continue with a default timezone or UTC) before merging.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread backend/utils/retrieval/tools/calendar_tools.py Outdated
@ZachL111

Copy link
Copy Markdown
Contributor Author

Good catch, you are right. The timezone lookup (a Firestore read offloaded via run_blocking) was unguarded, so a lookup failure would abort the whole tool and the user would get an error instead of their events. I factored it into _get_user_display_tz(uid), which wraps the lookup in try/except and falls back to UTC, so the events still render and times are labeled UTC when the user's timezone cannot be read. Added a test that the lookup raising still returns the UTC display tz. Pushed in be39d05.

@Git-on-my-level Git-on-my-level added the needs-maintainer-review Needs a human maintainer to review/approve (e.g. stacked, product, or architecture judgment) label Jun 28, 2026
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Thanks @ZachL111 — nice, clean fix. The three helpers (_resolve_display_tz, _format_event_dt, _get_user_display_tz) are well-factored: correct tz conversion, naive→UTC coercion so the model never sees an unlabeled wall-clock time, UTC fallback on a missing/invalid zone, and the day-boundary case is covered. I also appreciate that you addressed cubic's point about the unguarded Firestore lookup by wrapping it in _get_user_display_tz with a UTC fallback so a tz lookup failure can't abort the whole tool.

I verified the helpers directly and the 8 new unit tests pass. A couple of small notes for when this lands:

  • _format_event_dt renders the full IANA zone name (e.g. America/Los_Angeles) as the label. That's unambiguous and good for the model; just flagging it's the zone id rather than an abbreviation like PDT, in case the rendering is revisited later.
  • The notification_db import is only used for get_user_time_zone; fine as-is, just noting the cross-module dependency.

One process note: this looks like it builds on the still-open #8483 (same #4643 follow-up, action-item timestamps). I'm leaving a positive signal rather than approving so a maintainer can confirm the sequencing/merge order between the two. Not blocking on the code itself.

@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Independent static review of the diff against main:

  • Dependency resolution is valid: database.notifications.get_user_time_zone(uid), utils.executors.run_blocking, and db_executor all exist with matching signatures, so the new _get_user_display_tz(uid) call resolves cleanly at runtime.
  • The logger.warning(...) in _get_user_display_tz references a name defined later in the module, but since it is only resolved at call time (not import time) this is fine — verified it resolves to the module-level logger.
  • _format_event_dt tz conversion + naive→UTC coercion is correct, and the UTC fallback path is genuinely defensive (a tz lookup failure renders events in labeled UTC rather than aborting the tool).
  • The ENCRYPTION_SECRET value in the new test is the pre-existing repo-wide test fixture (~98 files), not a new secret.

No code concerns from me. Holding off on formal approval only because this builds on the still-open #8483 (same #4643 follow-up) — leaving to a maintainer to confirm the merge order between the two. Tagging along with the existing needs-maintainer-review.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend bug fix (#4643): render calendar event times in user timezone — approve (carries needs-maintainer-review label).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-maintainer-review Needs a human maintainer to review/approve (e.g. stacked, product, or architecture judgment)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants