Skip to content
Go to console
Go to console

The dashboard shows times in the repo's own zone

Decision record 0089

Amends 0029 (every time on the dashboard is in UTC) and 0027 (the failure line’s time ends in UTC). Built as slice 5.25.

Every time Sluiceway wrote was UTC: the scan line, the last full scan, the waiting-run line (0086), the failure line on a row and the trail, with Times are in UTC. under its heading. The owner, who runs Sluiceway on a real repo and does not live in UTC, asked for his own time (issue 203): every read cost a conversion in his head.

Decision

  • dashboard.timeZone names the zone, as an IANA name such as Europe/Brussels. The default is UTC, and a dashboard without the key, or with UTC named outright, is byte for byte what Sluiceway wrote before. No existing dashboard moves.
  • The zone belongs to the repo, not the reader. One issue is read by everyone and the body is the same bytes for all of them, so it cannot follow a browser or a GitHub profile. The line under the Recently deployed heading names the zone it used: Times are in Europe/Brussels., and Times are in UTC. as before.
  • A time that stands alone says its offset. The trail’s times lean on the zone line. This is the rule Sluiceway already followed with UTC, kept as it is: the scan line, the last full scan, the line about a run waiting for a runner (0086) and the failure line each end in the offset from UTC at that moment, 2026-07-21 12:02 UTC+2, 2026-01-15 09:52 UTC+1, 2026-09-21 14:22 UTC+5:30, UTC-3:30, and UTC when the zone is at UTC then, as London in winter. The trail’s lines say no zone and no offset, because the line under the heading says it once for all of them. The offset is picked over the abbreviation because an abbreviation is ambiguous (IST is three zones), is missing for most of the world’s zones in the runtime’s data, and varies between runtimes; an offset is exact and reads the same everywhere. The offset is picked over saying the zone only once because a failure line is a carried row (0004): a scan that does not preview the stack writes the row back as it is, so a line written before the zone changed stays until the row is drawn again, and it must still be true then. With the offset on it, it is.
  • The markers keep UTC ISO. scan-at, full-scan-at and the at of an outside deploy are written with toISOString() whatever the zone, so a body written under one zone parses under another, and no stored time is ever rewritten. The zone is a setting of the renderer only: the diff hash, the row markers and every decision are the same under any zone, and a row’s bytes depend on the zone only through the time its failure line shows, as they already depended on the time.
  • Daylight saving is the runtime’s zone data, applied per instant. The instant is kept and only its rendering changes: each time is shown with the offset its zone had at that instant, so a January and a July deploy of Europe/Brussels read UTC+1 and UTC+2, and the trail’s times are each the wall clock of their own instant. The year a trail line leaves out is the scan’s year in the zone, so a scan just after midnight on New Year’s Day in the zone drops the new year, not the old one.
  • A name that is not a zone fails the config, like every other key, with an example: dashboard.timeZone: "Europe/Brusels" is not a time zone. Write an IANA name, such as Europe/Brussels or America/New_York, or leave the key out for UTC. An offset such as +02:00 or UTC+2 fails too, even on a runtime that would take it, because it has no daylight saving and would be wrong half the year. The name is kept as the repo wrote it.
  • The zone is checked against the zone data of the runtime that runs the action. The action runs on node24, whose builds carry full ICU zone data, as GitHub’s runners do. A runtime built without it knows UTC alone. There, any other name fails the config with the same message, so the job goes red on the first run and the dashboard never falls back to UTC in silence. UTC itself never asks the zone data: the default renders the way it did before, with toISOString().
  • What does not change. The job summaries, the preview pages, the comments and the notifications write no time of day today; the times a reader sees there, of a run or a check, are GitHub’s own and follow the reader’s settings. The result file and the webhook message carry durations and no time of day. If any of them ever writes one, it is in the repo’s zone by this record. The warm good-news line stays picked by the UTC day of the scan (0075): it is a rotation, not a time a person reads, and a zone must not change which line a dashboard shows.

Considered

  • The reader’s own zone. Impossible in an issue body, which is one text for everyone, and GitHub offers no markup for a time that renders per reader.
  • The zone once, on the zone line, and no offset anywhere. Shorter, but a carried failure line from before a zone change would then show a time in the old zone under a line that names the new one.
  • An abbreviation such as CEST. Ambiguous, absent for many zones, and different between runtimes, so the bytes could change with the runtime.
  • A zone per stack or per reader list. Nothing asked for it, and one dashboard with two zones would need a zone on every time.