Duration Parser For Human Time Strings

Parse compact durations such as 1h30m, 500ms or 2.5s into milliseconds with unit validation and clear syntax errors.

TypescriptConfig Management

Code

snippet
const UNITS: Readonly<Record<string, number>> = {
  ms: 1,
  s: 1_000,
  m: 60_000,
  h: 3_600_000,
  d: 86_400_000,
  w: 604_800_000,
};

export function parseDuration(input: string): number {
  if (typeof input !== "string") throw new TypeError("input must be a string");
  const text = input.trim().toLowerCase();
  if (text === "") throw new SyntaxError("duration must not be empty");
  if (text.startsWith("-") || text.startsWith("+")) {
    throw new RangeError("signed durations are not supported");
  }

  const pattern = /(\d+(?:\.\d+)?)\s*(ms|s|m|h|d|w)/g;
  let total = 0;
  let lastIndex = 0;
  let matched = false;
  let match: RegExpExecArray | null;
  while ((match = pattern.exec(text)) !== null) {
    const gap = text.slice(lastIndex, match.index);
    if (gap.trim() !== "") throw new SyntaxError("invalid duration: " + input);
    const amount = Number(match[1]);
    const unit = match[2];
    total += amount * (UNITS[unit] ?? 0);
    lastIndex = pattern.lastIndex;
    matched = true;
  }
  if (!matched || text.slice(lastIndex).trim() !== "") {
    throw new SyntaxError("invalid duration: " + input);
  }
  if (!Number.isFinite(total)) throw new RangeError("duration is too large");
  return Math.round(total);
}