/** * Date formatting utilities for the Antaram app. * * Uses date-fns for absolute formats and a hand-rolled relative time * function to avoid pulling in too many locale files. */ import { format, isToday, isYesterday, isThisYear, parseISO } from 'date-fns'; // ─── Relative Time ─────────────────────────────────────────────────────────── /** * Returns a human-friendly relative time string. * * Examples: * - "just now" (< 60 seconds) * - "2 min ago" (< 60 minutes) * - "1 hr ago" (< 24 hours) * - "Yesterday" (yesterday) * - "3 days ago" (< 7 days) * - "Mar 15" (same year, >= 7 days) * - "Mar 15, 2024" (different year) */ export function formatRelativeTime(dateStr: string): string { const date = parseISO(dateStr); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffSec = Math.floor(diffMs / 1000); const absDiffSec = Math.abs(diffSec); // Future dates (shouldn't happen often, but handle gracefully) if (diffSec < 0) { if (absDiffSec < 60) return 'in a moment'; if (absDiffSec < 3600) { const mins = Math.floor(absDiffSec / 60); return `in ${mins} min`; } if (absDiffSec < 86400) { const hrs = Math.floor(absDiffSec / 3600); return `in ${hrs} hr${hrs > 1 ? 's' : ''}`; } return formatDate(dateStr); } // Past dates if (diffSec < 60) return 'just now'; const diffMin = Math.floor(diffSec / 60); if (diffMin < 60) return `${diffMin} min ago`; const diffHr = Math.floor(diffMin / 60); if (diffHr < 24) return `${diffHr} hr${diffHr > 1 ? 's' : ''} ago`; if (isYesterday(date)) return 'Yesterday'; const diffDays = Math.floor(diffHr / 24); if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`; // Fall back to short date format if (isThisYear(date)) return format(date, 'MMM d'); return format(date, 'MMM d, yyyy'); } // ─── Absolute Date ─────────────────────────────────────────────────────────── /** * Format as "Mar 29, 2026" */ export function formatDate(dateStr: string): string { const date = parseISO(dateStr); return format(date, 'MMM d, yyyy'); } /** * Format as "Mar 29, 2026 at 10:42 AM" */ export function formatDateTime(dateStr: string): string { const date = parseISO(dateStr); if (isThisYear(date)) { return format(date, 'MMM d \'at\' h:mm a'); } return format(date, 'MMM d, yyyy \'at\' h:mm a'); } // ─── Time Only ─────────────────────────────────────────────────────────────── /** * Format as "10:42 AM" */ export function formatTime(dateStr: string): string { const date = parseISO(dateStr); return format(date, 'h:mm a'); } /** * Format as "10:42:03 AM" (with seconds) */ export function formatTimeWithSeconds(dateStr: string): string { const date = parseISO(dateStr); return format(date, 'h:mm:ss a'); } // ─── Short Helpers ─────────────────────────────────────────────────────────── /** * Returns "Today", "Yesterday", or the formatted date. */ export function formatDayLabel(dateStr: string): string { const date = parseISO(dateStr); if (isToday(date)) return 'Today'; if (isYesterday(date)) return 'Yesterday'; if (isThisYear(date)) return format(date, 'EEEE, MMM d'); return format(date, 'EEEE, MMM d, yyyy'); } /** * Format as "10 Mar 2026 14:30" (for chat message timestamps) */ export function formatChatTimestamp(dateStr: string): string { const date = parseISO(dateStr); if (isToday(date)) return format(date, 'HH:mm'); if (isYesterday(date)) return 'Yesterday'; if (isThisYear(date)) return format(date, 'd MMM'); return format(date, 'd MMM yyyy'); } /** * Duration in minutes to human-readable string. * Example: 125 → "2 hr 5 min" */ export function formatDuration(minutes: number): string { if (minutes < 1) return '< 1 min'; const hrs = Math.floor(minutes / 60); const mins = Math.round(minutes % 60); if (hrs === 0) return `${mins} min`; if (mins === 0) return `${hrs} hr`; return `${hrs} hr ${mins} min`; }