Skip to content

SCA-364: render Desktop Chat SQL timestamps in the user timezone - #12326

Open
Git-on-my-level wants to merge 3 commits into
mainfrom
agent/m1-studio-cursor-grok-4-6/702451a8
Open

SCA-364: render Desktop Chat SQL timestamps in the user timezone#12326
Git-on-my-level wants to merge 3 commits into
mainfrom
agent/m1-studio-cursor-grok-4-6/702451a8

Conversation

@Git-on-my-level

@Git-on-my-level Git-on-my-level commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Desktop Chat treated UTC-naive SQLite DATETIME cells as local wall-clock, so “when did I last open Claude?” quoted 7:59:51 PM for a 3:59:51 PM EDT instant.

This PR converts timestamp / *At cells in execute_sql (and the matching Windows renderer) into the user’s timezone with an explicit IANA/offset label, repairs SQL “today/yesterday” examples so filters stay UTC-vs-UTC, and keeps the live clock on the per-turn # Current Time prefix instead of the cached system prompt.

Test plan

  • Pinned clock 2026-08-27T19:59:51Z + America/New_York: execute_sql / formatRows contain 3:59:51 PM and a zone token; must not present unlabeled 7:59:51 PM
  • ChatPromptsTests — cached desktop prompt has no {current_datetime_str}; SQL examples compare UTC columns to UTC bounds
  • Windows desktopChatPrompt.test.ts + sql.test.ts (88 tests)
  • make preflight on this branch

Line-Count-Exception: desktop/macos/Desktop/Sources/Providers/ChatToolExecutor.swift | 3439 -> 3441 | thread display timezone through execute_sql and keep daily-recap bounds UTC-vs-UTC

Product invariants affected

  • INV-AUTH-1
  • INV-CHAT-1

Failure-Class: FC-machine-timezone-timestamp-in-prompt

Closes #12321

Related: #4643, #12236 (do not close)

SCA-364

Review in cubic

Git-on-my-level and others added 3 commits August 28, 2026 05:31
execute_sql dumped UTC-naive SQLite DATETIME cells, so Desktop Chat
quoted 7:59 PM for a 3:59 PM Eastern event. Convert timestamp/*At cells
in the tool result, keep filters UTC-vs-UTC, and put the live clock only
on the per-turn # Current Time prefix.

Failure-Class: FC-machine-timezone-timestamp-in-prompt
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
The new formatter is used by execute_sql result projection on the
chat-hermetic path; list it so the flow-coverage ratchet stays closed.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
origin/main currently fails desktop-swiftlint on the IUO added with the
owner-fenced history seed. Use a regular optional so the lint gate can
run on this branch.

Failure-Class: none
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
const parsed = Date.parse(`${naive[1]}T${naive[2]}Z`)
if (Number.isFinite(parsed)) return new Date(parsed)
}
const iso = Date.parse(trimmed)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On Windows this turns a date-only cell into the previous calendar day: formatSqlTimestampCell('captureDate', '2026-08-27', 'America/New_York') returns 2026-08-26 8:00:00 PM EDT. The Swift parser only accepts values that include a time, so please keep date-only values unchanged (or render them as calendar dates without timezone conversion) and add this fixture.

lines.push(
row
.map((cell, index) => {
const formatted = formatSqlTimestampCell(columns[index] ?? '', cell, timeZone)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This per-cell path constructs two Intl.DateTimeFormat instances. On this Windows machine, 20,000 timestamp cells (200 rows x 100 model-controlled aliases) took 2.09 seconds synchronously; because execute_sql caps rows but not columns and runs in Electron main, prompt-injected SQL can freeze the UI. Please cap columns or total rendered cells and cache formatter instances by timezone.

* Eastern event (#12321). Always convert in an injected IANA zone and label it.
*/

const TIMESTAMP_COLUMN = /^(timestamp|ts|.*(?:At|_at|Date|_date))$/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TIMESTAMP and TS are not recognized here because this regex is case-sensitive, while Swift explicitly matches them case-insensitively. A model can alias ts AS TIMESTAMP and leave the exact unlabeled-UTC bug on Windows; a case-insensitive match plus a parity fixture would close it.

@tianmind-studio

Copy link
Copy Markdown
Contributor

#12349 has now landed the narrower formatter. While validating its interaction with this PR's macOS changes, I reproduced the remaining double-localization/local-day boundary gap as #12350 and opened #12351 as a focused post-merge follow-up, including a pinned non-UTC fixture and runtime SELECT-projection guard; this PR still contains the broader cross-surface work.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop chat shows UTC screenshot timestamps as local time

2 participants