Before submitting
Area
apps/web
Steps to reproduce
- Open Settings and set Time format to 24-hour. Alternatively, keep System default on an OS or browser that uses a 24-hour clock (for example
en-GB or nb-NO).
- Open Usage and select Past 24 hours.
- Look at the window label in the top bar, the chart's x-axis labels, the chart tooltip, and the first column of the breakdown table.
Expected behavior
The hourly labels follow the Time format setting, like the chat timestamps and the limit reset times on the same page. With 24-hour or a 24-hour system default, the labels show 14 or 14:00, not 2 PM.
Actual behavior
All hourly labels on the Past 24 hours view use the US 12-hour clock for all three Time format values: 2 PM, 2 PM today, Oct 3, 2 PM to Oct 4, 2 PM.
The limit reset times on the same page follow the setting. They use formatUpcomingTimestamp(window.resetsAt, timestampFormat, now) (UsageLimits.tsx#L90-L97).
Root cause
The hourly helpers in packages/shared/src/usageFormat.ts take only a time zone. They create Intl.DateTimeFormat("en-US", { hour: "numeric", ... }) with no hour12 or hourCycle. The en-US locale forces a 12-hour clock, so neither the setting nor the system locale has an effect:
The rest of the web app formats times through apps/web/src/timestampFormat.ts (L3-L22). Those helpers take timestampFormat from usePrimarySettings((settings) => settings.timestampFormat). They also use the host locale from #6190. UsagePage and UsageProviderChart do not read timestampFormat, and no prop or context passes it to the hourly helpers.
Affected call sites (Usage > Past 24 hours)
The helpers were added in #6170. The mobile Usage screen also calls formatHourShort (UsageRouteScreen.tsx#L526, L544). Mobile has no Time format setting, so that path keeps the current behavior unless the fix changes the default.
Other web surfaces that ignore the setting
These surfaces use the runtime locale default instead of timestampFormat:
The closed PR #12867 covered most of this second list but did not touch the Usage page. A maintainer closed it on 2026-10-01 for missing current UI evidence. I report the Usage page as the primary defect here, and I list the other surfaces for completeness.
Secondary observation
The usage helpers also hard-code English month names. formatDateTimeShort uses en-US, and formatDayShort (usageFormat.ts#L64) has a fixed "Jan" to "Dec" table. An nb-NO user sees Oct 3, while the runtime locale gives 3. okt.. This can be intentional, as with the English tooltip dates in #10256. I do not ask for a change to it here.
Suggested fix (sketch)
Resolve the setting to a boolean in the web app and pass it to the shared helpers. The parameter is optional, so mobile and existing tests keep their current output.
// apps/web/src/timestampFormat.ts
+export function resolveHour12(timestampFormat: TimestampFormat): boolean {
+ if (timestampFormat !== "locale") return timestampFormat === "12-hour";
+ return (
+ new Intl.DateTimeFormat(timestampLocale, { hour: "numeric" }).resolvedOptions().hour12 ?? false
+ );
+}
// packages/shared/src/usageFormat.ts
-export function formatHourShort(hourStart: string, timeZone?: string): string {
+export function formatHourShort(hourStart: string, timeZone?: string, hour12?: boolean): string {
...
- const hourFormat = dateTimeFormatter("en-US", { ...options, hour: "numeric" });
+ const hourFormat = dateTimeFormatter("en-US", {
+ ...options,
+ hour: "numeric",
+ ...(hour12 === undefined ? {} : { hour12 }),
+ });
// same for the timeZoneName formatter, formatDateTimeShort, and formatRelativeHourShort
// UsagePage.tsx and UsageProviderChart.tsx
+const timestampFormat = usePrimarySettings((settings) => settings.timestampFormat);
+const hour12 = resolveHour12(timestampFormat);
-formatHourShort(period.hourStart, window.timeZone)
+formatHourShort(period.hourStart, window.timeZone, hour12)
With en-US and hour12: false, an hour-only label renders as 14. If 14:00 reads better on the axis, add minute: "2-digit" in 24-hour mode only.
Impact
Cosmetic issue
Version or commit
main @ eac52f0
Environment
Code inspection on main @ eac52f0, plus a Node.js 24.19.0 run (V8 with full ICU) of the unmodified usageFormat.ts and timestampFormat.ts modules. I did not check this in the packaged desktop app or a browser.
Logs or stack traces
# Instant 2026-10-04T12:37:00Z (14:37 in Europe/Oslo), timeZone "Europe/Oslo".
# The window is 2026-10-03T12:37Z to 2026-10-04T12:37Z.
== TZ=Europe/Oslo LANG=LC_ALL=nb_NO.UTF-8
default locale: nb-NO hour12 default: h23
usageFormat.formatHourShort : "2 PM"
usageFormat.formatHourShort (DST) : "2 AM GMT+2"
usageFormat.formatDateTimeShort : "Oct 3, 2 PM to Oct 4, 2 PM"
usageFormat.formatRelativeHourShort : "2 PM today" "2 PM yesterday"
timestampFormat.formatShortTimestamp(locale): "14:37"
timestampFormat.formatShortTimestamp(24-hour): "14:37"
timestampFormat.formatShortTimestamp(12-hour): "2:37 p.m."
== TZ=Europe/Oslo LANG=LC_ALL=en_GB.UTF-8
default locale: en-GB hour12 default: h23
usageFormat.formatHourShort : "2 PM"
usageFormat.formatHourShort (DST) : "2 AM GMT+2"
usageFormat.formatDateTimeShort : "Oct 3, 2 PM to Oct 4, 2 PM"
usageFormat.formatRelativeHourShort : "2 PM today" "2 PM yesterday"
timestampFormat.formatShortTimestamp(locale): "14:37"
timestampFormat.formatShortTimestamp(24-hour): "14:37"
timestampFormat.formatShortTimestamp(12-hour): "2:37 pm"
Workaround
None in the app. The hourly labels use the 12-hour clock for all three Time format values.
Before submitting
Area
apps/web
Steps to reproduce
en-GBornb-NO).Expected behavior
The hourly labels follow the Time format setting, like the chat timestamps and the limit reset times on the same page. With 24-hour or a 24-hour system default, the labels show
14or14:00, not2 PM.Actual behavior
All hourly labels on the Past 24 hours view use the US 12-hour clock for all three Time format values:
2 PM,2 PM today,Oct 3, 2 PM to Oct 4, 2 PM.The limit reset times on the same page follow the setting. They use
formatUpcomingTimestamp(window.resetsAt, timestampFormat, now)(UsageLimits.tsx#L90-L97).Root cause
The hourly helpers in
packages/shared/src/usageFormat.tstake only a time zone. They createIntl.DateTimeFormat("en-US", { hour: "numeric", ... })with nohour12orhourCycle. Theen-USlocale forces a 12-hour clock, so neither the setting nor the system locale has an effect:formatHourShort: usageFormat.ts#L135-L161formatDateTimeShort: usageFormat.ts#L164-L174formatRelativeHourShortcalls both: usageFormat.ts#L176-L202The rest of the web app formats times through
apps/web/src/timestampFormat.ts(L3-L22). Those helpers taketimestampFormatfromusePrimarySettings((settings) => settings.timestampFormat). They also use the host locale from #6190.UsagePageandUsageProviderChartdo not readtimestampFormat, and no prop or context passes it to the hourly helpers.Affected call sites (Usage > Past 24 hours)
formatDateTimeShort)formatHourShort)formatRelativeHourShort) and x-axis labels (formatHourShort)The helpers were added in #6170. The mobile Usage screen also calls
formatHourShort(UsageRouteScreen.tsx#L526, L544). Mobile has no Time format setting, so that path keeps the current behavior unless the fix changes the default.Other web surfaces that ignore the setting
These surfaces use the runtime locale default instead of
timestampFormat:new Date(request.startedAt).toLocaleTimeString()`Resets ${new Date(resetAt).toLocaleString()}`(the chat banner for usage limits)new Date(...).toLocaleString()Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" })for pairing-link timesThe closed PR #12867 covered most of this second list but did not touch the Usage page. A maintainer closed it on 2026-10-01 for missing current UI evidence. I report the Usage page as the primary defect here, and I list the other surfaces for completeness.
Secondary observation
The usage helpers also hard-code English month names.
formatDateTimeShortusesen-US, andformatDayShort(usageFormat.ts#L64) has a fixed"Jan"to"Dec"table. Annb-NOuser seesOct 3, while the runtime locale gives3. okt.. This can be intentional, as with the English tooltip dates in #10256. I do not ask for a change to it here.Suggested fix (sketch)
Resolve the setting to a boolean in the web app and pass it to the shared helpers. The parameter is optional, so mobile and existing tests keep their current output.
With
en-USandhour12: false, an hour-only label renders as14. If14:00reads better on the axis, addminute: "2-digit"in 24-hour mode only.Impact
Cosmetic issue
Version or commit
main @ eac52f0
Environment
Code inspection on main @ eac52f0, plus a Node.js 24.19.0 run (V8 with full ICU) of the unmodified
usageFormat.tsandtimestampFormat.tsmodules. I did not check this in the packaged desktop app or a browser.Logs or stack traces
Workaround
None in the app. The hourly labels use the 12-hour clock for all three Time format values.