/** * Date / time форматирование для UI мессенджера. * * Все функции принимают **unix-seconds** (совместимо с `Message.timestamp`, * который тоже в секундах). Для ms-таймштампов делаем нормализацию внутри. */ // English short month names ("Jun 17, 2025"). const MONTHS_SHORT = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; function sameDay(a: Date, b: Date): boolean { return ( a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() ); } /** * Day-bucket label for chat separators. * "Today" / "Yesterday" / "Jun 17, 2025" * * @param ts unix-seconds */ export function dateBucket(ts: number): string { const d = new Date(ts * 1000); const now = new Date(); const yday = new Date(); yday.setDate(now.getDate() - 1); if (sameDay(d, now)) return 'Today'; if (sameDay(d, yday)) return 'Yesterday'; return `${MONTHS_SHORT[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`; } /** * Короткое relative-time под углом bubble ("29m", "14m", "3h", "2d", "12:40"). * * @param ts unix-seconds */ export function relTime(ts: number): string { const now = Date.now(); const diff = now - ts * 1000; if (diff < 60_000) return 'now'; if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m`; if (diff < 24 * 3_600_000) return `${Math.floor(diff / 3_600_000)}h`; if (diff < 7 * 24 * 3_600_000) return `${Math.floor(diff / (24 * 3_600_000))}d`; const d = new Date(ts * 1000); return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; } /** * Похоже на relTime, но принимает как unix-seconds, так и unix-ms. * Используется в chat-list tiles (там timestamp бывает в ms от addedAt). */ export function formatWhen(ts: number): string { // Heuristic: > 1e12 → уже в ms, иначе seconds. const sec = ts > 1e12 ? Math.floor(ts / 1000) : ts; return relTime(sec); } /** "HH:MM" — одна и та же локаль, без дня. */ export function formatHM(ts: number): string { const d = new Date(ts * 1000); return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; }