/** * RelativeTimeDisplay * * Deterministic relative time formatting. */ export class RelativeTimeFormatter { /** * Formats a date relative to "now". * "now" must be passed as an argument for determinism. */ static format(date: string | Date, now: Date): string { const d = typeof date === 'string' ? new Date(date) : date; const diffMs = d.getTime() - now.getTime(); const diffHours = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60)); const diffDays = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60 * 24)); if (diffMs < 0) { if (diffHours < 1) return 'Just now'; if (diffHours < 24) return `${diffHours}h ago`; if (diffDays === 1) return 'Yesterday'; if (diffDays < 7) return `${diffDays}d ago`; return this.formatAbsolute(d); } else { if (diffHours < 1) return 'Starting soon'; if (diffHours < 24) return `In ${diffHours}h`; if (diffDays === 1) return 'Tomorrow'; if (diffDays < 7) return `In ${diffDays} days`; return this.formatAbsolute(d); } } private static formatAbsolute(date: Date): string { const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; return `${months[date.getUTCMonth()]} ${date.getUTCDate()}`; } }