f3aae61ad87c61a230c8807f5b468235f557d68a
Phase 7 — single source of truth for date display. Backed by Intl.DateTimeFormat
(no new dep — built into Node 18+ + every supported browser). Replaces 96
ad-hoc `new Date(x).toLocaleDateString('en-GB')` calls scattered across the
codebase.
src/lib/utils/format-date.ts (new):
formatDate(value, preset?, options?) — primary helper
formatDateRange(start, end, options?) — collapsed range strings
formatRelative(value, options?) — "3 hours ago" / "in 2 days"
Presets (named so callers don't memorize Intl options shape):
date.short 12 May
date.medium 12 May 2026
date.long Monday, 12 May 2026
date.iso 2026-05-12 (TZ-aware ISO date, no time)
datetime.short 12 May 14:30
datetime.medium 12 May 2026 14:30
datetime.long Monday, 12 May 2026 at 14:30 UTC
datetime.iso 2026-05-12T14:30:00.000Z
time 14:30
Defensive defaults:
- null/undefined/Invalid Date → '—' (overridable via { fallback })
- locale defaults to en-GB (settles audit-flagged en-US/en-GB drift)
- tz passthrough to Intl.DateTimeFormat timeZone field (any IANA name)
Sample sweep (3 sites — proves the pattern; remaining 93 sites can be
migrated opportunistically when files are touched):
src/lib/services/expense-pdf.service.ts:608 default subheader
src/lib/services/document-templates.ts:364 {{interest.dateFirstContact}}
src/lib/services/document-templates.ts:374-378 {{interest.date*Signed}}
The 93 remaining sites are listed in docs/BACKLOG.md §G with the rule:
"replace as you touch the file" — gives compounding cleanup without
a single risky 90-file commit.
tests/unit/format-date.test.ts (new) — 17 tests:
- fallback handling (null/undefined/invalid/explicit)
- date.iso correctness in UTC + non-UTC timezones
- datetime.iso = full ISO string
- en-GB locale-formatted output
- timezone respect across NY/UTC
- time-only preset
- Date/string/epoch ms inputs all accepted
- formatDateRange same-year collapse, different-year keep, missing ends
- formatRelative: just-now / minutes / hours / days / future / invalid
1315/1315 vitest green (+17 new from format-date.test.ts).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
TypeScript
98.7%
HTML
1%
CSS
0.1%
Shell
0.1%