/** 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". Truncating and single-unit on * purpose, 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`; }