export const formatRelativeTime = (timestampMs: number, nowMs: number): string => { if (!timestampMs) return ''; const diff = Math.max(0, nowMs - timestampMs); const s = Math.floor(diff / 1000); if (s < 60) return 'just now'; const m = Math.floor(s / 60); if (m < 60) return `${m}m ago`; const h = Math.floor(m / 60); if (h < 24) return `${h}h ago`; const d = Math.floor(h / 24); if (d < 7) return `${d}d ago`; // Spencer, 2026-09-10, looking at a thread list where one row read `5/29/2026` between two // that read `4d ago`: *"why does receptionist one have a date of 5/29/2026 instead of following the // Xd/Xw/Xy format the others follow?"* // // A DATE IN A COLUMN OF AGES IS A DIFFERENT QUESTION ANSWERED. Every other row says how long ago; // that one said when, and the reader has to do the subtraction themselves to compare it with the row // above it. The fallback was there because a week felt like the end of usefully-relative time. It is // not: a thread list is sorted by recency, so `15w ago` places a row against its neighbours // instantly and a date does not. // // WEEKS THEN YEARS, WITH NO MONTHS, because those are the three units named. A month is not a // fixed number of days and picking one silently makes `4w` and `1mo` disagree about the same // instant; if months are wanted they are a decision, not an omission. const w = Math.floor(d / 7); if (w < 52) return `${w}w ago`; return `${Math.floor(d / 365)}y ago`; };