Human-Readable Duration Formatting

Convert milliseconds into compact durations such as 1h 5m 20s with unit limits, short labels and zero handling.

JavascriptData Integrity

Code

snippet
const UNITS = [
  ["day", 86400000],
  ["hour", 3600000],
  ["minute", 60000],
  ["second", 1000],
];

// Human-readable duration formatting for elapsed time.
export function formatDuration(milliseconds, options = {}) {
  if (typeof milliseconds !== "number" || !Number.isFinite(milliseconds) || milliseconds < 0) {
    throw new RangeError("duration must be a non-negative finite number");
  }
  const { maxUnits = UNITS.length, separator = " ", short = false } = options;
  if (!Number.isInteger(maxUnits) || maxUnits < 1) {
    throw new RangeError("maxUnits must be a positive integer");
  }
  let remaining = Math.floor(milliseconds);
  const parts = [];
  for (const [name, size] of UNITS) {
    if (parts.length >= maxUnits) break;
    const amount = Math.floor(remaining / size);
    remaining -= amount * size;
    if (amount === 0 && parts.length === 0) continue;
    if (amount === 0) continue;
    const label = short ? name[0] : " " + name + (amount === 1 ? "" : "s");
    parts.push(amount + label);
  }
  if (parts.length === 0) return short ? "0s" : "0 seconds";
  return parts.join(separator);
}

export function formatDurationClock(milliseconds) {
  if (typeof milliseconds !== "number" || !Number.isFinite(milliseconds) || milliseconds < 0) {
    throw new RangeError("duration must be a non-negative finite number");
  }
  const totalSeconds = Math.floor(milliseconds / 1000);
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = totalSeconds % 60;
  return [hours, minutes, seconds].map((part) => String(part).padStart(2, "0")).join(":");
}