/** * Format an elapsed millisecond count as a compact human string: * < 60s -> "12s" * < 1h -> "5m 23s" * >= 1h -> "2h 05m" * Negatives clamp to 0s (clock skew tolerance). */ export function formatDuration(ms: number): string { if (!Number.isFinite(ms) || ms < 0) ms = 0; const totalSeconds = Math.floor(ms / 1000); if (totalSeconds < 60) return `${totalSeconds}s`; const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, '0')}s`; const hours = Math.floor(minutes / 60); const mins = minutes % 60; return `${hours}h ${String(mins).padStart(2, '0')}m`; } /** * Convenience: elapsed since an ISO timestamp, formatted. Returns null when * the anchor is null so callers can `{#if}` on it. */ export function elapsedSince(iso: string | null, now: number): string | null { if (!iso) return null; return formatDuration(now - new Date(iso).getTime()); }