mobileapp / src /utils /dateFormat.ts
Antaram Dev Bot
feat: complete ANTARAM.ORG ride-sharing app frontend
5c876be
/**
* 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`;
}