#3737·buzz

Desktop: 12-hour/24-hour clock preference — should the default follow the OS, and how far should it reach?

Author: HuggeKCreated Jul 30, 2026Updated Sep 17, 2026

Opening this as the discussion venue for #3736 (GitHub Discussions is turned off on this repo, so an issue seemed like the right place). The implementation is already up as a draft PR; the open questions below are design calls I'd rather have decided by maintainers than guessed at.

Motivation

Every time-of-day label in the desktop app is produced by an Intl.DateTimeFormat pinned to en-US, so the app always renders 2:34 PM. Anyone who reads time on a 24-hour clock — most of Europe, and plenty of people elsewhere — has no way to change it. It shows up in message rows, inbox labels, agent transcripts, project panels, search results, and the moderation queue.

Proposed solution

A Clock row in Settings → Appearance with System / 12-hour / 24-hour, backed by a localStorage preference that follows the same useSyncExternalStore shape as the existing threadViewModePreference. Every hour-bearing formatter routes through one of two helpers so there's a single place that decides the hour cycle. Draft PR: #3736.

Open questions

  1. Should the default be 12-hour or System? The PR defaults to 12-hour because that is byte-for-byte what installs render today: upgrading changes nothing until someone picks a clock, and unit/screenshot tests stay deterministic regardless of the host's locale. The counter-argument is that System is what most users would expect, and the app already reads the host locale elsewhere. It's a one-line change either way — I went with the conservative option, but I'd switch on request.

  2. Should system also relax the pinned en-US locale? Right now it resolves only the hour cycle from the host locale and keeps en-US for month and weekday names, so choosing 24-hour doesn't half-translate the UI into a language Buzz isn't localized for. If broader locale support is on the roadmap, this preference should probably fold into that instead of standing alone.

  3. How far should a change reach into already-rendered views? The channel timeline, thread panel, and Home inbox bake formatted strings into memoized rows, so they subscribe to the preference and repaint immediately. Surfaces that format during render (agent transcripts, search results, project panels, drafts, moderation queue) pick the new clock up on their next render — in practice when you leave Settings. Making those repaint instantly means having the individual row components subscribe; I left it out to keep the diff focused, and because AppShell.tsx sits at 999 of the 1000-line check-file-sizes budget so the blunt app-shell-wide subscription isn't available.

  4. Mobile. The Flutter app has its own DateFormat('h:mm a') formatters under mobile/lib/features/channels/ and its own Appearance section. Should that ship in the same change, or as a follow-up that mirrors whatever shape gets agreed here?

Alternatives considered

  • A boolean "Use 24-hour time" toggle instead of three options — simpler, but then there's no way to say "follow my OS", and the toggle's default has the same question baked in.
  • Deriving the clock purely from the host locale with no setting at all — no UI surface to argue about, but it takes away the choice from anyone whose OS locale disagrees with how they want to read chat, and it would silently change what existing installs display.

Additional context

Searched open and closed issues and PRs for "24-hour", "24h", "12-hour", "time format", "clock format", "AM/PM" and "timestamp" before starting — none found.

Verification on the PR branch: pnpm typecheck clean, pnpm test 3793 passing / 0 failing, biome check clean on all changed files, and the check-file-sizes / check-px-text / check-pubkey-truncation gates pass. No screenshots yet — developed on Windows, where the hermit toolchain doesn't bootstrap, so the Tauri app couldn't be launched to capture one.

Generated with Claude Code