45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
export function formatBytes(n: number): string {
|
|
const num = Number(n) || 0;
|
|
if (num < 1024) return `${num} B`;
|
|
const units = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
|
|
let v = num / 1024;
|
|
let i = 0;
|
|
while (v >= 1024 && i < units.length - 1) {
|
|
v /= 1024;
|
|
i++;
|
|
}
|
|
return `${v.toFixed(2)} ${units[i]}`;
|
|
}
|
|
|
|
function pad(n: number): string {
|
|
return n < 10 ? `0${n}` : `${n}`;
|
|
}
|
|
|
|
// Deterministic, timezone-independent date+time formatter.
|
|
// Uses UTC getters so the server (UTC) and client (local TZ) render
|
|
// byte-identical text, avoiding React hydration mismatches (error #425).
|
|
// Output format: "YYYY-MM-DD HH:MM UTC".
|
|
export function formatDateTime(s: string | null | undefined): string {
|
|
if (!s) return '—';
|
|
const d = new Date(s);
|
|
if (Number.isNaN(d.getTime())) return '—';
|
|
const date = `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(
|
|
d.getUTCDate(),
|
|
)}`;
|
|
const time = `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`;
|
|
return `${date} ${time} UTC`;
|
|
}
|
|
|
|
// Date-only deterministic UTC formatter. Output format: "YYYY-MM-DD UTC".
|
|
export function formatDateOnly(s: string | null | undefined): string {
|
|
if (!s) return '—';
|
|
const d = new Date(s);
|
|
if (Number.isNaN(d.getTime())) return '—';
|
|
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(
|
|
d.getUTCDate(),
|
|
)} UTC`;
|
|
}
|
|
|
|
// Backwards-compatible alias: existing call sites render date+time.
|
|
export const formatDate = formatDateTime;
|