Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 2,372 Bytes
e59d91d | 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 | /** Parse ISO / Postgres timestamptz strings from APIs. */
export function parseApiDateTime(value: string | null | undefined): Date | null {
if (!value?.trim() || value === '—') return null
const d = new Date(value.trim())
return Number.isNaN(d.getTime()) ? null : d
}
const absoluteFormatter = new Intl.DateTimeFormat(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
})
/** Local calendar + clock, e.g. "May 25, 2026, 8:55 PM". */
export function formatDateTimeAbsolute(value: string | null | undefined): string {
const d = parseApiDateTime(value)
if (!d) return value?.trim() || '—'
return absoluteFormatter.format(d)
}
function formatRelativeToNow(date: Date): string {
const diffMs = date.getTime() - Date.now()
const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' })
const absSec = Math.abs(Math.round(diffMs / 1000))
if (absSec < 45) return rtf.format(Math.round(diffMs / 1000), 'second')
if (absSec < 45 * 60) return rtf.format(Math.round(diffMs / 60_000), 'minute')
if (absSec < 22 * 3_600) return rtf.format(Math.round(diffMs / 3_600_000), 'hour')
if (absSec < 6 * 86_400) return rtf.format(Math.round(diffMs / 86_400_000), 'day')
return absoluteFormatter.format(date)
}
/** Compact age for live dashboards, e.g. ``5m ago``, ``2h ago``. */
export function formatAgoCompact(
value: string | null | undefined,
nowMs = Date.now(),
): string {
const d = parseApiDateTime(value)
if (!d) return '—'
const sec = Math.max(0, Math.floor((nowMs - d.getTime()) / 1000))
if (sec < 60) return `${Math.max(1, sec)}s ago`
const m = Math.floor(sec / 60)
if (m < 60) return `${m}m ago`
const h = Math.floor(m / 60)
if (h < 48) return `${h}h ago`
const days = Math.floor(h / 24)
return `${days}d ago`
}
/** "Updated" line: relative when within a week, otherwise absolute. */
export function formatUpdatedAt(value: string | null | undefined): {
display: string
title: string
} {
const d = parseApiDateTime(value)
if (!d) {
const fallback = value?.trim() || '—'
return { display: fallback, title: fallback }
}
const absolute = formatDateTimeAbsolute(value)
const ageDays = Math.abs(d.getTime() - Date.now()) / 86_400_000
return {
display: ageDays < 7 ? formatRelativeToNow(d) : absolute,
title: absolute,
}
}
|