File size: 4,577 Bytes
5c876be | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /**
* 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`;
}
|