Skip to content

Comments

fix: use local timezone for all user-facing datetime displays#1906

Open
amikofalvy wants to merge 5 commits intomainfrom
fix/local-timestamps-everywhere
Open

fix: use local timezone for all user-facing datetime displays#1906
amikofalvy wants to merge 5 commits intomainfrom
fix/local-timestamps-everywhere

Conversation

@amikofalvy
Copy link
Collaborator

@amikofalvy amikofalvy commented Feb 10, 2026

Summary

Follow-up to the hydration fix (#1863 / 6fb0715) and initial traces local-time fix (#1903 / 73d79bd). The hydration fix forced all Intl.DateTimeFormat calls to UTC, but this made timestamps across the UI display in UTC instead of the user's local timezone. The traces fix added { local: true } opt-in for the traces area; this PR applies the same pattern to all remaining datetime renders.

Changes

High priority — formatDateTime/formatDateTimeTable calls displaying specific times in UTC (now local):

  • evaluation-run-config-results.tsx — conversation created timestamps
  • evaluation-job-results.tsx — conversation created timestamps
  • dataset-items-table.tsx — item updated timestamps
  • runs/[runId]/page.tsx — run and conversation created timestamps
  • github/[installationId]/page.tsx — installation created/updated timestamps

Server component fix:

  • evaluations/jobs/[configId]/page.tsx — created a LocalDateTimeTable client component since { local: true } has no effect in server components (server always renders UTC on Vercel)

Replaced local formatDate implementations with shared utility (fixes hydration risk):

  • view-mcp-server-details-shared.tsx — removed local formatDate using toLocaleDateString(), updated callers (view-mcp-server-details-user-scope.tsx, view-mcp-server-details-project-scope.tsx) to use formatDateTimeTable from shared utility with { local: true }
  • work-app-github-installations-list.tsx — removed local formatDate, now imports shared formatDate with { local: true }
  • triggers/invocations-table.tsx — removed local formatDate, now imports shared formatDateTime with { local: true }

Test plan

  • Verify timestamps display in local timezone on evaluation run config results page
  • Verify timestamps display in local timezone on evaluation job results page
  • Verify timestamps display in local timezone on dataset items table
  • Verify timestamps display in local timezone on dataset run details page
  • Verify timestamps display in local timezone on GitHub installation details page
  • Verify timestamps display in local timezone on evaluation job page header
  • Verify MCP server details pages show local time without hydration errors
  • Verify GitHub installations list shows local dates without hydration errors
  • Verify trigger invocations table shows local times without hydration errors
  • No hydration warnings in browser console

Made with Cursor

Follow-up to the hydration fix (6fb0715) and initial traces fix (73d79bd).
Ensures all remaining datetime renders show local time instead of UTC:

- evaluation run config results, evaluation job results
- dataset items table, dataset run details
- GitHub installation details page
- MCP server details (removed local formatDate, use shared utility)
- GitHub installations list (removed local formatDate, use shared utility)
- Trigger invocations table (removed local formatDate, use shared utility)
- Created LocalDateTimeTable client component for server component contexts

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot
Copy link

changeset-bot bot commented Feb 10, 2026

🦋 Changeset detected

Latest commit: 91539e5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@inkeep/agents-manage-ui Patch
@inkeep/agents-api Patch
@inkeep/agents-cli Patch
@inkeep/agents-core Patch
@inkeep/agents-manage-mcp Patch
@inkeep/agents-mcp Patch
@inkeep/agents-sdk Patch
@inkeep/agents-work-apps Patch
@inkeep/ai-sdk-provider Patch
@inkeep/create-agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agents-api Ready Ready Preview, Comment Feb 10, 2026 9:16pm
agents-manage-ui Ready Ready Preview, Comment Feb 10, 2026 9:16pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
agents-docs Skipped Skipped Feb 10, 2026 9:16pm

Request Review

@inkeep
Copy link
Contributor

inkeep bot commented Feb 10, 2026

No docs changes detected.

This PR is an internal UI bug fix for datetime display formatting (UTC → local timezone) that doesn't impact any public APIs, SDK interfaces, or documented features.

- external-agents/view-external-agent-details.tsx: replaced local formatDate
  with shared formatDateTimeTable + { local: true }
- evaluation-jobs/evaluation-jobs-list.tsx: replaced toLocaleDateString calls
  with shared formatDate + { local: true } (hydration safety)
- evaluations/jobs/[configId]/page.tsx: replaced toLocaleDateString() with
  shared formatDate (consistent server-side formatting)
- github/[installationId]/page.tsx: added { local: true } to repo.createdAt

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

2 Key Findings | Risk: Medium

🔴❗ Critical (1) ❗🔴

  • 🔴 Critical: .changeset/fix-local-timestamps-everywhere.md:1-3 Changeset uses incorrect package name — will likely fail during release

🟠⚠️ Major (1) 🟠⚠️

  • 🟠 Major: evaluation-jobs-list.tsx:174 Missing { local: true } for updatedAt timestamp

🟡 Minor (1) 🟡

🟡 1) multi-file Several other formatDate calls not updated in this "all remaining" sweep

Issue: The PR title says "use local timezone for all user-facing datetime displays" and the description mentions "applies the same pattern to all remaining datetime renders." However, the consistency review found 12+ other files with formatDate() calls that still don't have { local: true }:

  • agents/agent-item.tsx:53formatDate(createdAt)
  • api-keys/expiration-indicator.tsx:48,58formatDate(expiresAt)
  • datasets/dataset-item.tsx:37formatDate(createdAt)
  • projects/project-item.tsx:51formatDate(createdAt)
  • data-components/data-component-item.tsx:40formatDate(createdAt)
  • external-agents/external-agent-item.tsx:164formatDate(externalAgent.createdAt)
  • credentials/credential-item.tsx:135formatDate(createdAt)
  • evaluators/evaluators-list.tsx:103formatDate(evaluator.updatedAt)
  • artifact-components/artifact-component-item.tsx:42formatDate(createdAt)
  • mcp-servers/mcp-tool-item.tsx:205formatDate(tool.createdAt)
  • evaluation-run-configs/evaluation-run-configs-list.tsx:141formatDate(runConfig.updatedAt)

Why: If these are intentionally out of scope (e.g., item cards use date-only format where UTC vs local is less noticeable), that's reasonable — but the PR title suggests a comprehensive sweep.

Fix: Either:

  1. Update these files to use { local: true } for completeness, or
  2. Adjust the PR title/description to clarify scope (e.g., "fix local timezone for datetime displays on detail pages")

Refs:

  • PR description — "applies the same pattern to all remaining datetime renders"

💭 Consider (1) 💭

💭 1) formatDateAgo Consider adding { local: true } to formatDateAgo calls

Issue: The formatDateAgo utility also supports { local: true } but calls throughout the codebase don't use it. For recent timestamps (showing "3h ago"), timezone doesn't matter. But for older dates (>30 days), the fallback renders an absolute date in UTC.

Why: Lower priority since relative time is timezone-agnostic, but worth considering for consistency.

Fix: Add { local: true } to formatDateAgo() calls, or document that fallback dates intentionally use UTC.


💡 APPROVE WITH SUGGESTIONS

Summary: The approach is sound and the pattern application is correct, but there are two issues that should be addressed: (1) the changeset uses the wrong package name which will likely cause it to be ignored during release, and (2) one formatDate call in a file that was already modified was missed. Both have 1-click suggestion fixes in the inline comments above. The minor finding about other files is for the author to decide on scope.

Discarded (4)
Location Issue Reason Discarded
local-datetime.tsx Missing className prop for extensibility Too nitpicky for a simple utility component; can be added later if needed
evaluations/jobs/[configId]/page.tsx:34-35 Server component formatDate without { local: true } This is in a server component for date-only display; UTC rendering may be intentional for consistency with how date ranges are stored
formatDateAgo fallback dates in multiple files formatDateAgo calls without { local: true } Flagged as "Consider" instead — relative time is timezone-agnostic, only fallback to absolute dates is affected
evaluation-jobs-list.tsx:98-99 Already uses { local: true } Positive observation, not an issue
Reviewers (4)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-standards 1 0 0 0 1 0 0
pr-review-frontend 1 0 0 0 1 0 0
pr-review-consistency 4 1 1 0 0 0 2
pr-review-devops 2 0 0 0 1 0 1
Total 8 1 1 0 2 0 3

Note: The evaluation-jobs-list.tsx:174 issue was identified by multiple reviewers (standards, frontend, consistency) and merged into a single inline comment.

@github-actions github-actions bot deleted a comment from claude bot Feb 10, 2026
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

0 Key Findings | Risk: Low

This is a delta review scoped to changes since the last automated review (fd42417aeaf1248f).

Delta Changes

The only change in this delta was applying the 1-click suggestion to fix the changeset package name:

  • 'agents-manage-ui'"@inkeep/agents-manage-ui"

The CRITICAL issue from the prior review is now resolved.

🕐 Pending Recommendations (1)

💭 Consider (1)

💭 1) meta Author feedback on changeset workflow

Issue: The author noted that the original changeset file was created manually instead of using the pnpm bump script, which led to the incorrect package name format.

Why: The pnpm bump script ensures correct package names, proper formatting, and consistent changeset structure. Manual creation bypasses these guardrails.

Fix: This is feedback for future AI agent sessions — when creating changesets, always use:

pnpm bump <patch|minor|major> --pkg <package> "<message>"

Refs:


💡 APPROVE WITH SUGGESTIONS

Summary: The delta successfully addresses the CRITICAL changeset issue from the prior review. One MAJOR issue remains pending from the prior review (missing { local: true } at line 174 in evaluation-jobs-list.tsx). The author may choose to address this or scope it out intentionally. Overall, the PR is in good shape for the intended purpose.

Discarded (0)

No items discarded in this delta review.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
Total 0 0 0 0 0 0 0

Note: No sub-agent reviewers dispatched — delta was a single changeset fix that didn't require specialized review.

The { local: true } option causes hydration mismatches when used in client
components that receive data from server components via props. During SSR,
Intl.DateTimeFormat defaults to UTC (Vercel's server timezone), but the
client renders local time — React keeps the server-rendered UTC version.

This replaces direct { local: true } calls with LocalDateTime wrapper
components that:
1. Initially render UTC (matching server HTML — no hydration mismatch)
2. Switch to local time after mount via useEffect

Components with client-side data fetching (useState/useEffect) are
unaffected and keep using { local: true } directly since timestamps
only render after mount.

Affected files (SSR'd from server component props):
- invocations-table.tsx → LocalDateTime
- dataset-items-table.tsx → LocalDateTimeTable
- evaluation-run-config-results.tsx → LocalDateTimeTable
- evaluation-job-results.tsx → LocalDateTimeTable
- view-external-agent-details.tsx → LocalDateTimeTable
- view-mcp-server-details-user-scope.tsx → LocalDateTimeTable
- view-mcp-server-details-project-scope.tsx → LocalDateTimeTable

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

0 Key Findings | Risk: Low

This is a delta review scoped to changes since the last automated review (eaf1248fa49c747b).

Delta Changes

The delta contains a single commit (a49c747b) that introduces a proper hydration-safe pattern for local timezone rendering:

local-datetime.tsx refactor:

  • Changed from a simple passthrough wrapper to a useState/useEffect pattern
  • Initial render uses UTC (matching server-rendered HTML)
  • Client-side useEffect updates to local time after mount
  • Exports four variants: LocalDate, LocalDateTime, LocalDateTimeTable, LocalDateAgo

Component migrations (7 files):

  • Switched from formatDateTime*(..., { local: true }) to using the new wrapper components
  • This ensures hydration-safe behavior when data comes from SSR'd server components

Both pr-review-standards and pr-review-frontend reviewers found no issues with the delta implementation. The hydration-safe pattern is correctly implemented and follows React/Next.js best practices.

🕐 Pending Recommendations (1)

  • 🟠 evaluation-jobs-list.tsx:174 Missing { local: true } for formatDate(jobConfig.updatedAt) — this line was flagged in the initial review and remains unaddressed (the file was not part of this delta)

💡 APPROVE WITH SUGGESTIONS

Summary: The delta successfully implements a hydration-safe pattern for local timezone rendering — well done! 🎉 The LocalDateTimeBase component correctly uses useState/useEffect to avoid hydration mismatches. One MAJOR issue from the prior review remains pending at evaluation-jobs-list.tsx:174, which the author may address in a follow-up or scope out intentionally.

Discarded (0)

No items discarded in this delta review.

Reviewers (2)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-frontend 0 0 0 0 0 0 0
pr-review-standards 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: Clean delta — both reviewers validated the hydration-safe pattern implementation with no concerns.

@github-actions github-actions bot deleted a comment from claude bot Feb 10, 2026
The previous useState/useEffect approach may not have been updating the DOM
in all cases. This new approach uses three layers:

1. Client renders local time directly (no useEffect delay)
2. suppressHydrationWarning accepts server/client text mismatch
3. useEffect + ref.textContent as a DOM patching fallback

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel vercel bot temporarily deployed to Preview – agents-docs February 10, 2026 21:14 Inactive
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

0 Key Findings | Risk: Low

This is a delta review scoped to changes since the last automated review (a49c747b91539e52).

Delta Changes

The delta contains a single commit (91539e52) that refactors the LocalDateTimeBase component in local-datetime.tsx:

Previous implementation (flash of UTC):

  • Used useState/useEffect pattern
  • Initial render showed UTC (matching server HTML)
  • useEffect updated state to local time after mount
  • User briefly saw UTC before switching to local

New implementation (immediate local time):

  • Uses suppressHydrationWarning to allow client to immediately render local time
  • Adds useRef/useEffect fallback that patches DOM textContent if React's hydration doesn't update it
  • No flash of UTC — user sees local time immediately

Both pr-review-frontend and pr-review-standards reviewers found no issues with the delta. The suppressHydrationWarning pattern is a standard React approach for timezone-dependent content where server/client mismatch is intentional. The useEffect fallback is a reasonable defensive measure.

🕐 Pending Recommendations (1)

  • 🟠 evaluation-jobs-list.tsx:174 Missing { local: true } for formatDate(jobConfig.updatedAt) — this was flagged in the initial review and remains unaddressed (the file was not modified in this delta)

✅ APPROVE

Summary: The delta successfully improves the hydration-safe pattern for local timezone rendering — users now see local time immediately instead of a brief flash of UTC. The implementation is clean and follows React best practices. 🎉 One MAJOR issue remains pending from prior reviews (evaluation-jobs-list.tsx:174), which the author may choose to address in this PR or scope out intentionally.

Discarded (0)

No items discarded in this delta review.

Reviewers (2)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-frontend 0 0 0 0 0 0 0
pr-review-standards 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: Clean delta — both reviewers validated the suppressHydrationWarning + useRef/useEffect fallback pattern with no concerns.

@github-actions github-actions bot deleted a comment from claude bot Feb 10, 2026
const ref = useRef<HTMLSpanElement>(null);
const localDisplay = fn(dateString, { local: true });

// Fallback: ensure DOM is updated to local time after mount
Copy link
Collaborator

Choose a reason for hiding this comment

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

@claude is this fallback necessary?

Copy link
Contributor

@claude claude bot Feb 10, 2026

Choose a reason for hiding this comment

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

Claude finished @shagun-singh-inkeep's task in 47s —— View job


Todo List

  • Read and analyze the local-datetime.tsx implementation
  • Evaluate the necessity of the useRef/useEffect fallback
  • Provide detailed explanation

Analysis: Is the fallback necessary?

Short answer: No, the fallback is not necessary and can be safely removed.

Why the fallback isn't needed

When using suppressHydrationWarning on a React element:

  1. React handles the content update: During hydration, React detects the mismatch between server HTML (UTC time) and client render (local time). With suppressHydrationWarning, React suppresses the warning but still updates the DOM to match the client-rendered content.

  2. The fallback never executes: The condition ref.current.textContent !== localDisplay will never be true after React's hydration completes because React has already updated the text content to match localDisplay.

How suppressHydrationWarning works

<span suppressHydrationWarning>
  {localDisplay}  // Client renders local time immediately
</span>
  • Server renders: UTC time (e.g., "2024-01-15 14:30 UTC")
  • Client hydrates: Local time (e.g., "2024-01-15 09:30 EST")
  • React's behavior: Updates DOM to local time, suppresses the hydration warning

Proof the fallback is redundant

The useEffect check:

if (ref.current && ref.current.textContent !== localDisplay) {
  ref.current.textContent = localDisplay;  // This never executes
}

By the time useEffect runs (after mount), React has already reconciled the DOM. The text content will already match localDisplay, making the condition always false.

Recommended simplification

Remove lines 33, 36-41:

function LocalDateTimeBase({ dateString, format }: { dateString: string; format: FormatFn }) {
  const fn = formatFns[format];
  const localDisplay = fn(dateString, { local: true });

  return (
    <span suppressHydrationWarning>
      {localDisplay}
    </span>
  );
}

This simpler version works identically because suppressHydrationWarning already ensures React handles the server/client mismatch properly.

Edge case consideration

The only theoretical scenario where a fallback might be useful is if there's a React bug where suppressHydrationWarning fails to update the DOM. However:

  • This would be a critical React bug affecting many applications
  • No such issues are documented in React 18/19
  • The current fallback wouldn't reliably fix such a bug anyway

Recommendation: Remove the unnecessary fallback for cleaner, simpler code. The suppressHydrationWarning prop alone is the correct and sufficient solution.

);
}

export function LocalDate({ dateString }: { dateString: string }) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this function is dead code i believe

return <LocalDateTimeBase dateString={dateString} format="dateTimeTable" />;
}

export function LocalDateAgo({ dateString }: { dateString: string }) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this function is also dead code i believe

return <LocalDateTimeBase dateString={dateString} format="date" />;
}

export function LocalDateTime({ dateString }: { dateString: string }) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

since this is only used in invocations-table.tsx and that file is a 'use client' we can just use formatDateTime(date, { local: true }) right? Or I may be misunderstanding the point of this function

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.

2 participants