/** Unix seconds → localized date-time. `locale`/`timeZone` exist for deterministic tests. */ export function formatTime(unixSeconds: number, locale?: string, timeZone?: string): string { return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "medium", timeZone, }).format(new Date(unixSeconds * 1000)); } const BYTE_UNITS = ["KiB", "MiB", "GiB", "TiB"] as const; export function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; let value = bytes; let unit: string = BYTE_UNITS[0]; for (const next of BYTE_UNITS) { unit = next; value /= 1024; if (value < 1024) break; } return `${value.toFixed(1)} ${unit}`; } const AGE_UNITS = [ { seconds: 86400, suffix: "d" }, { seconds: 3600, suffix: "h" }, { seconds: 60, suffix: "m" }, ] as const; /** * Seconds of elapsed time → a coarse "3h ago". Truncating and single-unit on * purpose: this labels a snapshot the caller renders once, so a reader must not * take it for a live count. Nothing re-renders it as it ages. */ export function formatAge(seconds: number): string { for (const unit of AGE_UNITS) { if (seconds >= unit.seconds) return `${Math.floor(seconds / unit.seconds)}${unit.suffix} ago`; } return `${Math.floor(seconds)}s ago`; } /** * Seconds of elapsed time → a coarse "3h", the same single truncated unit as * `formatAge` without the "ago". For a span the caller labels itself, as in * "active for 3h". A negative span reads "0s": clock skew is not a duration. */ export function formatDuration(seconds: number): string { for (const unit of AGE_UNITS) { if (seconds >= unit.seconds) return `${Math.floor(seconds / unit.seconds)}${unit.suffix}`; } return `${Math.max(0, Math.floor(seconds))}s`; } /** Microseconds → milliseconds with one decimal, e.g. 1234 → "1.2 ms". */ export function formatMicros(micros: number): string { return `${(micros / 1000).toFixed(1)} ms`; }