Skip to main content

Overview

Parsing is the reverse of formatting: it converts human-readable duration strings like “2h 30m” into numeric milliseconds. Enhanced MS provides the parseDuration() function and the ms() factory function to handle this conversion.

How parsing works

The parsing process uses language-specific regular expressions to extract time values from strings (~/workspace/source/src/parse/index.ts:18):
export function parseDuration(
  duration: string,
  language: Language = getLanguage('en'),
) {
  const matches = duration.toLowerCase().match(language.matcherRegex);
  if (!matches || matches.length === 0) return 0;

  let total = 0;
  for (let i = 0; i < matches.length; i += 2) {
    const [amount, unit] = matches.slice(i, i + 2) as [string, string];
    const ms = language.timeUnits[unit]?.ms;
    if (ms) total += Number(amount) * ms;
  }
  return total;
}

Step-by-step breakdown

  1. Convert to lowercase - Makes parsing case-insensitive
  2. Match patterns - Use regex to find number-unit pairs
  3. Sum values - Convert each pair to milliseconds and add them up
  4. Return total - Return the sum or 0 if no valid matches

Basic usage

import { parseDuration, getLanguage } from 'enhanced-ms';

parseDuration("2h 30m");
// 9000000 (2 hours + 30 minutes in milliseconds)

parseDuration("2 hours 30 minutes");
// 9000000

parseDuration("1 day, 5 hours, 30 minutes");
// 105000000

Supported formats

The parser is flexible and accepts various input formats:

Abbreviated units

ms("2h 30m 15s");
// 9015000

ms("1d 12h");
// 129600000

Full unit names

ms("2 hours 30 minutes 15 seconds");
// 9015000

ms("1 day 12 hours");
// 129600000

Mixed formats

ms("1d 30 minutes 15s");
// 88215000 (mixing abbreviations and full names)

With punctuation

The parser handles common punctuation:
ms("1 day, 2 hours, 30 minutes");
// 95400000

ms("2h, 30m");
// 9000000

Decimal values

The parser uses language-specific decimal separators defined in the language configuration.
// English (uses . as decimal separator)
ms("1.5 hours");
// 5400000 (1.5 hours = 90 minutes)

// German (uses , as decimal separator)
const msDE = createMs({ language: 'de' });
msDE("1,5 stunden");
// 5400000

Matching patterns

Each language defines which strings match each unit (~/workspace/source/src/languages/en.ts:1). For example, English accepts:
// Hour variations
ms("1 hour");   // ✓
ms("2 hours");  // ✓
ms("1h");       // ✓

// Minute variations
ms("1 minute"); // ✓
ms("2 minutes"); // ✓
ms("1m");       // ✓

// Second variations
ms("1 second"); // ✓
ms("2 seconds"); // ✓
ms("1s");       // ✓
The matcher regex is built dynamically from the language’s unit definitions (~/workspace/source/src/languages/helpers/make-language.ts:24):
const matcherRegex = new RegExp(
  `(?![${decimalSeparator}${thousandSeparator}])` + // Don't match separators alone
  `[\\d${decimalSeparator}${thousandSeparator}]+|` + // Match numbers
  '(?<=\\s|\\d)((?:-)?(' + // Match units after space or digit
  Object.values(languageDefinition.units)
    .flatMap(({ matches }) => matches)
    .sort((a, b) => b.length - a.length) // Longer matches first
    .join('|') +
  '))',
  'gi',
);
Longer unit names are matched first to prevent “months” from matching as “m” (minutes).

Order and accumulation

Units can appear in any order and are accumulated:
ms("30m 2h");
// 9000000 (2h + 30m)

ms("15s 30m 2h");
// 9015000 (2h + 30m + 15s)
Duplicate units are also accumulated:
ms("1h 30m 30m");
// 7200000 (1h + 30m + 30m = 2h total)

Localized parsing

You can parse strings in any supported language:
import { createMs } from 'enhanced-ms';

// German
const msDE = createMs({ language: 'de' });
msDE("2 stunden 30 minuten");
// 9000000

// French
const msFR = createMs({ language: 'fr' });
msFR("2 heures 30 minutes");
// 9000000

// Spanish
const msES = createMs({ language: 'es' });
msES("2 horas 30 minutos");
// 9000000
Each language has its own set of accepted unit names and abbreviations. See the Localization guide for details.

Edge cases

The parser handles various edge cases gracefully:

Invalid strings

Returns 0 for unrecognized formats:
ms("invalid");
// 0

ms("xyz");
// 0

ms("");
// 0

Partial matches

Extracts valid parts and ignores the rest:
ms("wait 2h then 30m later");
// 9000000 (ignores "wait" and "then" and "later")

Numbers without units

Ignored (numbers must be followed by units):
ms("42");
// 0 (no unit specified)

ms("42 minutes");
// 2520000 (unit specified)

Case insensitivity

Parsing works regardless of case:
ms("2H 30M");
// 9000000

ms("2 HOURS 30 MINUTES");
// 9000000

All supported units

Enhanced MS can parse all time units from nanoseconds to millennia:
UnitExampleMilliseconds
Nanosecond"1ns"0.000001
Microsecond"1μs"0.001
Millisecond"1ms"1
Second"1s"1,000
Minute"1m"60,000
Hour"1h"3,600,000
Day"1d"86,400,000
Week"1w"604,800,000
Month"1mo"2,592,000,000
Year"1y"31,536,000,000
Decade"1dec"315,360,000,000
Century"1c"3,153,600,000,000
Millennium"1mil"31,536,000,000,000
Be careful with ambiguous abbreviations like “m” (minute vs month). Enhanced MS prioritizes minutes for “m” and requires “mo” for months.

Build docs developers (and LLMs) love