parse-duration
Parses human-readable duration strings like '1h 20m' into milliseconds, with pluggable locales.
Repository Health
Technical Analysis
parse-duration is a small, dependency-free JavaScript library that converts human-readable duration strings — like ‘1h 20m’, ‘2e3s’, or ‘-1hr 40mins’ — into a numeric duration. It matches every value/unit pair in a string with a single regular expression, resolves each unit against a lookup table, and sums the results, so compound, noisy, or negative expressions parse correctly in one pass.
Beyond the default English units, the library exposes a swappable parse.unit table that ships with locale files for Spanish, French, German, Portuguese, Russian, Chinese, Japanese, and Indonesian, each defining its own unit names plus decimal/group separators. Output can be requested in any supported unit via a second argument, letting callers get milliseconds, seconds, or minutes back from the same call.
What You Get
- Zero-dependency parser distributed as ESM
- Locale-aware unit table (swap
parse.unitfor non-English locales) - Output-format argument to get results back in ms, s, m, or any defined unit
- Bundled TypeScript type declarations
- Guards against parsing dangerous prototype-property names like ‘constructor’
Common Use Cases
- Parsing CLI or config duration flags like ‘—timeout 30s’
- Converting user-entered scheduling input (‘in 2 hours’) to a millisecond delay
- Normalizing durations pulled from logs or third-party API responses
- Building cache TTL or rate-limit window configs from human-readable strings
Under The Hood
Architecture
parse-duration is a single exported function (index.js) backed by a swappable parse.unit lookup table rather than a class hierarchy or plugin system. A single Unicode-aware regular expression walks the input string extracting value/unit pairs; a module-level cache (groupRE, placeholder, group) is rebuilt only when the active locale’s group/placeholder characters change, keeping repeated calls fast without re-deriving a new regex each time. Locale objects (locale/*.js) are plain objects — either created fresh via Object.create(null) (English) or extended from English via Object.create(en) (Spanish, German, etc.) — so the entire extension mechanism is “assign a new object to parse.unit”; there is no formal plugin registration. This keeps the surface area tiny, but couples every locale file and the caching logic tightly to the shape of the unit table (group/decimal/placeholder keys) — a rename there would require touching every locale.
Tech Stack
The package is pure ESM ("type": "module") with zero runtime dependencies; the only devDependency is tape for testing. There is no build/bundle step — package.json’s files field ships index.js, index.d.ts, and the locale/ directory as-authored source. Type declarations in index.d.ts are hand-written rather than compiled from TypeScript source, so they must be kept in sync manually. CI (GitHub Actions) runs npm test across Node 18, 20, and 22 on every push and PR to master.
Code Quality
test.js uses tape and exercises an extensive matrix of unit spellings (s/sec/second/seconds), compound and noisy strings, negative and exponential numbers, locale switching (es/de/en), custom locales without group/placeholder metadata, and explicit regression cases for numbers with long digit runs. Notably, several tests specifically guard against a class of prototype-pollution-style bugs — strings like ‘1constructor’ or ‘2call 3apply’ must return null rather than resolving through Object.prototype members. There is no linter or formatter configuration in the repo, and no code-coverage tooling, but the test suite’s edge-case density is unusually high for a package this size.
API Design
The public API is minimal and ergonomic: one default export, parse(str, format = 'ms'), with no configuration object or setup step required. Locale switching is a single assignment (parse.unit = es) rather than a constructor argument, which is convenient for global config but means locale state is shared/mutable at the module level rather than scoped per call. The README documents every supported input shape (compound, YouTube-style ‘1h20m0s’, comma-separated numbers, noisy text) directly against real output values, so onboarding requires reading a handful of inline examples rather than external docs.
Used by 5 apps in this directory
Jitsu
Data Engineering
Open-source, fully-scriptable data ingestion engine that streams events from web, apps, and APIs to any data warehouse in real time.
Midday
Invoicing Finance · Productivity
All-in-one AI-powered business operations platform for freelancers and solo entrepreneurs to manage invoicing, time tracking, banking, and financial intelligence.
Portainer
Devops
A lightweight, open-source web UI that puts Docker, Kubernetes, and Podman management within reach of any team—no CLI expertise required.
solidtime
Productivity · Invoicing Finance
Modern open-source time tracker for freelancers and agencies with invoicing, multi-org support, and Toggl/Clockify migration built in.
Trigger.dev
Automation · AI Development · Developer Tools
Build and deploy fully-managed AI agents and background jobs in TypeScript — with no timeouts, durable retries, real-time observability, and elastic scaling built in.