source dump of claude code
at main 81 lines 2.2 kB view raw
1/** 2 * Format an ISO timestamp for the brief/chat message label line. 3 * 4 * Display scales with age (like a messaging app): 5 * - same day: "1:30 PM" or "13:30" (locale-dependent) 6 * - within 6 days: "Sunday, 4:15 PM" (locale-dependent) 7 * - older: "Sunday, Feb 20, 4:30 PM" (locale-dependent) 8 * 9 * Respects POSIX locale env vars (LC_ALL > LC_TIME > LANG) for time format 10 * (12h/24h), weekday names, month names, and overall structure. 11 * Bun/V8's `toLocaleString(undefined)` ignores these on macOS, so we 12 * convert them to BCP 47 tags ourselves. 13 * 14 * `now` is injectable for tests. 15 */ 16export function formatBriefTimestamp( 17 isoString: string, 18 now: Date = new Date(), 19): string { 20 const d = new Date(isoString) 21 if (Number.isNaN(d.getTime())) { 22 return '' 23 } 24 25 const locale = getLocale() 26 const dayDiff = startOfDay(now) - startOfDay(d) 27 const daysAgo = Math.round(dayDiff / 86_400_000) 28 29 if (daysAgo === 0) { 30 return d.toLocaleTimeString(locale, { 31 hour: 'numeric', 32 minute: '2-digit', 33 }) 34 } 35 36 if (daysAgo > 0 && daysAgo < 7) { 37 return d.toLocaleString(locale, { 38 weekday: 'long', 39 hour: 'numeric', 40 minute: '2-digit', 41 }) 42 } 43 44 return d.toLocaleString(locale, { 45 weekday: 'long', 46 month: 'short', 47 day: 'numeric', 48 hour: 'numeric', 49 minute: '2-digit', 50 }) 51} 52 53/** 54 * Derive a BCP 47 locale tag from POSIX env vars. 55 * LC_ALL > LC_TIME > LANG, falls back to undefined (system default). 56 * Converts POSIX format (en_GB.UTF-8) to BCP 47 (en-GB). 57 */ 58function getLocale(): string | undefined { 59 const raw = 60 process.env.LC_ALL || process.env.LC_TIME || process.env.LANG || '' 61 if (!raw || raw === 'C' || raw === 'POSIX') { 62 return undefined 63 } 64 // Strip codeset (.UTF-8) and modifier (@euro), replace _ with - 65 const base = raw.split('.')[0]!.split('@')[0]! 66 if (!base) { 67 return undefined 68 } 69 const tag = base.replaceAll('_', '-') 70 // Validate by trying to construct an Intl locale — invalid tags throw 71 try { 72 new Intl.DateTimeFormat(tag) 73 return tag 74 } catch { 75 return undefined 76 } 77} 78 79function startOfDay(d: Date): number { 80 return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() 81}