41 lines · 1.2 KB
const SECONDS = 1000;
const MINUTE = 60 * SECONDS;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const MONTH = 30 * DAY;
const YEAR = 365 * DAY;
const KB = 1024;

const RELATIVE_UNITS: ReadonlyArray<[number, string]> = [
  [YEAR, "year"],
  [MONTH, "month"],
  [DAY, "day"],
  [HOUR, "hour"],
  [MINUTE, "minute"],
];

export function formatRelative(timestamp: number, now = Date.now()): string {
  const delta = now - timestamp;
  for (const [size, label] of RELATIVE_UNITS) {
    if (delta >= size) {
      const count = Math.floor(delta / size);
      return `${count} ${label}${count === 1 ? "" : "s"} ago`;
    }
  }
  return "just now";
}

export function formatDuration(start: number | null, end: number | null): string {
  if (!start) return "";
  const total = Math.max(0, Math.round(((end ?? Date.now()) - start) / SECONDS));
  const minutes = Math.floor(total / 60);
  return minutes > 0 ? `${minutes}m ${total % 60}s` : `${total}s`;
}

export function formatBytes(bytes: number): string {
  if (bytes < KB) return `${bytes} B`;
  if (bytes < KB * KB) return `${(bytes / KB).toFixed(1)} KB`;
  if (bytes < KB * KB * KB) return `${(bytes / KB / KB).toFixed(1)} MB`;
  return `${(bytes / KB / KB / KB).toFixed(1)} GB`;
}