feat: timezone setting — display timestamps in selected local timezone
All checks were successful
CI / test (pull_request) Successful in 13s
CI / build-dev (pull_request) Has been skipped

Add a Display section to the settings modal with a timezone dropdown.
Selection is persisted to localStorage and applied to all timestamps via
fmtDate (date-only) and fmtDateFull (date + time + TZ abbreviation, e.g.
"Mar 28, 2026, 2:48 PM EDT"). Changing the timezone live-re-renders the
current page. Defaults to UTC.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-28 14:53:20 -04:00
parent f16fb3e088
commit badd542bd7
4 changed files with 71 additions and 4 deletions

View File

@@ -88,24 +88,36 @@ describe('fmtDate', () => {
// ── fmtDateFull() ─────────────────────────────────────────────────────────────
function fmtDateFull(d) {
function fmtDateFull(d, tz = 'UTC') {
if (!d) return '—'
try {
return new Date(d).toLocaleString('en-US', {
year: 'numeric', month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit',
timeZone: tz, timeZoneName: 'short',
})
} catch (e) { return d }
}
describe('fmtDateFull', () => {
it('includes date and time components', () => {
const result = fmtDateFull('2024-03-15T14:30:00')
const result = fmtDateFull('2024-03-15T14:30:00Z')
expect(result).toMatch(/Mar/)
expect(result).toMatch(/2024/)
expect(result).toMatch(/\d{1,2}:\d{2}/)
})
it('includes the timezone abbreviation', () => {
expect(fmtDateFull('2024-03-15T14:30:00Z', 'UTC')).toMatch(/UTC/)
})
it('converts to the given timezone', () => {
// 2024-03-15 18:30 UTC = 2024-03-15 14:30 EDT (UTC-4 in March)
const result = fmtDateFull('2024-03-15T18:30:00Z', 'America/New_York')
expect(result).toMatch(/2:30/)
expect(result).toMatch(/EDT/)
})
it('returns — for null', () => {
expect(fmtDateFull(null)).toBe('—')
})