Skip to content

Render deploy History times in the viewer's local timezone - #375

Open
nickhammond wants to merge 2 commits into
mainfrom
nickhammond/local-timezone-deploy-times
Open

Render deploy History times in the viewer's local timezone#375
nickhammond wants to merge 2 commits into
mainfrom
nickhammond/local-timezone-deploy-times

Conversation

@nickhammond

Copy link
Copy Markdown
Member

What

On the deploy History / "Activity" page, each deploy's timestamp now renders in the viewer's own browser timezone, formatted client-side — instead of the organization's configured timezone.

Same deploy, same instant:

  • New York → Aug 12, 2026, 11:45 AM EDT
  • Tokyo → Aug 13, 2026, 12:45 AM JST

The timezone abbreviation is shown so it's unambiguous. No per-user configuration — it reads the browser's timezone automatically.

Why

Times were formatted server-side in the org's selected_time_zone, so anyone on a team spread across timezones had to convert in their head. This is per-viewer, resolved in each person's browser.

How

  • app/views/destinations/deploys.html.erb — add a local-time marker class to the deploy <time> element and emit the timestamp as .iso8601 (Ruby's default Time#to_s, e.g. "2026-08-12 15:45:00 UTC", is not reliably parseable by JS new Date()).
  • app/javascript/application.js — in the existing turbo:load handler, format time.local-time elements with Intl.DateTimeFormat(undefined, { dateStyle, timeStyle, timeZoneName }). undefined locale + no explicit timeZone makes it use the browser's own locale/timezone. An isNaN guard leaves the fallback in place on a bad date.

The server-rendered org-timezone string stays as the inner text — it's the no-JS fallback, overwritten client-side on load.

Scope / notes

  • History page only. The dashboard "X ago" panel and the timeago.js wiring are untouched.
  • Line 66's distance_of_time_in_words ("… before") is a duration between two deploys, already timezone-independent — left alone.
  • On-load only (no Turbo Stream re-format); Deploy has no broadcasts on this view, so nothing is missed.
  • No new dependency (Intl is built into the browser), no Stimulus controller, no system test.

Testing

  • bundle exec standardrb — clean.
  • Manual: open a deploy History page; time shows as absolute local time with tz abbreviation. Change OS/browser timezone and reload — the displayed time shifts; the org's selected_time_zone no longer affects it. With JS disabled, the server-rendered org-timezone fallback still shows.

The deploy History/Activity page formatted each deploy timestamp in the
organization's configured timezone, so viewers in other timezones had to
convert in their head. Format it client-side in the viewer's own browser
timezone instead.

- Add a local-time marker class to the deploy <time> element and emit the
  timestamp as iso8601 (Time#to_s is not reliably parseable by new Date()).
- In the existing turbo:load handler, format time.local-time elements with
  Intl.DateTimeFormat using the browser's own locale/timezone, guarding
  against invalid dates so the server-rendered fallback stays put.

The server-rendered org-timezone string remains as the no-JS fallback.

Copilot AI 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.

Pull request overview

Updates the deploy History (“Activity”) page to display deploy timestamps in each viewer’s local browser timezone (client-side), while keeping the existing server-rendered organization-timezone text as a no-JS fallback.

Changes:

  • Mark the History page <time> element with a local-time class and emit an ISO8601 datetime attribute for reliable JS parsing.
  • On turbo:load, format time.local-time elements using Intl.DateTimeFormat with the browser’s locale/timezone and include a timezone abbreviation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
app/views/destinations/deploys.html.erb Adds local-time class and switches <time datetime> to recorded_at.iso8601 for client-side parsing.
app/javascript/application.js Formats time.local-time timestamps on page load using Intl.DateTimeFormat in the viewer’s local timezone.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +19 to +24
document.querySelectorAll('time.local-time').forEach((el) => {
const date = new Date(el.getAttribute('datetime'));
if (!isNaN(date.getTime())) {
el.textContent = localTimeFormatter.format(date);
}
});
recorded_at is validated presence: true, but the column is nullable, so
legacy rows (predating that validation) can hold nil. Both the datetime
attribute and the visible timestamp call methods on it, so a nil would
raise and break the History page. Fall back to the record's created_at
(null: false) for the display.
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