// ── Format Utilities ─────────────────────────────────────────── /** * Format milliseconds as HH:MM:SS or MM:SS */ export function formatDuration(ms: number): string { if (ms <= 0) return '00:00'; const totalSeconds = Math.floor(ms / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; const pad = (n: number) => n.toString().padStart(2, '0'); if (hours > 0) { return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`; } return `${pad(minutes)}:${pad(seconds)}`; } /** * Format milliseconds as compact string: "2h 15m", "45m", "30s" */ export function formatDurationCompact(ms: number): string { if (ms <= 0) return '0s'; const totalSeconds = Math.floor(ms / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; if (hours > 0 && minutes > 0) return `${hours}h ${minutes}m`; if (hours > 0) return `${hours}h`; if (minutes > 0 && seconds > 0 && minutes < 5) return `${minutes}m ${seconds}s`; if (minutes > 0) return `${minutes}m`; return `${seconds}s`; } /** * Format a timestamp as relative time: "in 5m", "2h ago", "now" */ export function formatRelativeTime(targetTime: number, now: number = Date.now()): string { const diff = targetTime - now; const absDiff = Math.abs(diff); if (absDiff < 30_000) return 'now'; const compact = formatDurationCompact(absDiff); return diff > 0 ? `in ${compact}` : `${compact} ago`; } /** * Format time as HH:MM AM/PM */ export function formatTime(timestamp: number): string { const date = new Date(timestamp); return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, }); } /** * Format date as "Mon, Feb 27" */ export function formatDate(timestamp: number): string { const date = new Date(timestamp); return date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', }); }