npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

durate

v1.0.0

Published

Tiny millisecond conversion utility. Drop-in ms replacement with better types and more units.

Downloads

196

Readme

Tiny millisecond conversion utility. A drop-in ms replacement with better types and more units. < 3 kB brotli.

  • Drop-in compatible — swap ms for durate, everything works
  • TypeScript-firstDurationString branded type catches invalid strings at compile time
  • More units — months, weeks, and years in both parse and format
  • Universal — ESM, CJS, and IIFE browser global from a single package
  • Zero dependencies
  • < 3 kB brotli compressed

Install

npm install durate

Quick Start

import durate from 'durate';

durate('2 days')                     // 172_800_000
durate(172_800_000)                  // '2d'
durate(172_800_000, { long: true })  // '2 days'

API

parse

Converts a duration string to milliseconds. Supports single units, compound units, and ISO 8601 duration strings (auto-detected). Returns NaN on failure (or throws with { strict: true }).

import { parse } from 'durate';

parse('1h')                          // 3_600_000
parse('5 minutes')                   // 300_000
parse('1h 30m')                      // 5_400_000
parse('2d 6h 30m')                   // 196_200_000
parse('.5s')                         // 500
parse('-3h')                         // -10_800_000
parse('garbage')                     // NaN
parse('garbage', { strict: true })   // throws

// ISO 8601 durations are auto-detected
parse('PT1H30M')                     // 5_400_000
parse('P1D')                         // 86_400_000

// Bare numbers without a unit default to milliseconds
parse('100')                         // 100 (treated as 100ms, NOT seconds)

parseStrict

Compile-time type strictness with runtime validation — the input is typed as DurationString so TypeScript rejects invalid string literals before the code runs. At runtime, parseStrict delegates to parse(), which throws an Error for empty strings, non-string input, strings over 100 characters, and values that exceed Number.MAX_SAFE_INTEGER. Unrecognized-but-valid-looking strings return NaN as usual. The "strict" in the name refers to type-level strictness, but runtime guards are still active.

import { parseStrict } from 'durate';

parseStrict('5m')        // 300_000
parseStrict('garbage')   // TypeScript compile error

format

Converts milliseconds to a human-readable string. Supports compound and precision output.

import { format } from 'durate';

format(3_600_000)                                // '1h'
format(3_600_000, { long: true })                // '1 hour'
format(7_200_000, { long: true })                // '2 hours'
format(500)                                      // '500ms'

// Compound — multiple units
format(5_425_000, { compound: true })            // '1h 30m 25s'
format(5_425_000, { compound: true, long: true }) // '1 hour 30 minutes 25 seconds'
format(5_425_000, { compound: true, parts: 2 })  // '1h 30m'

// Precision — decimal places
format(5_400_000, { precision: 1 })              // '1.5h'
format(5_425_000, { precision: 2 })              // '1.51h'

// Template — format string with tokens
format(5_425_000, { template: 'HH:mm:ss' })     // '01:30:25'
format(5_425_000, { template: 'H[h] m[m] s[s]' }) // '1h 30m 25s'
format(90_061_500, { template: 'D[d] HH:mm:ss' }) // '1d 01:01:01'

durate (default export)

Bidirectional — string in, number out; number in, string out. Same as the default export.

import durate from 'durate';
// or
import { durate } from 'durate';

durate('2 days')                     // 172_800_000
durate(172_800_000)                  // '2d'
durate(172_800_000, { long: true })  // '2 days'

toUnit

Convert a duration to a specific unit. Accepts a duration string or milliseconds.

import { toUnit } from 'durate';

toUnit('2h', 'minutes')       // 120
toUnit(86_400_000, 'h')       // 24
toUnit('1h 30m', 'm')         // 90
toUnit('1w', 'days')          // 7
toUnit('1y', 'months')        // 12
toUnit('garbage', 'ms')       // NaN

parseISO

Parse an ISO 8601 duration string into milliseconds. Returns NaN for invalid input, never throws.

import { parseISO } from 'durate';

parseISO('PT1H30M')         // 5_400_000
parseISO('P1DT12H')         // 129_600_000
parseISO('P1Y2M3DT4H5M6S') // 37_091_106_000
parseISO('PT0.5S')          // 500
parseISO('not iso')          // NaN

formatISO

Format milliseconds as an ISO 8601 duration string. Uses days as the largest unit (no weeks/months/years) for unambiguous round-tripping. Throws for non-finite numbers.

import { formatISO } from 'durate';

formatISO(5_400_000)        // 'PT1H30M'
formatISO(129_600_000)      // 'P1DT12H'
formatISO(500)              // 'PT0.5S'
formatISO(0)                // 'PT0S'
formatISO(-3_600_000)       // '-PT1H'

Arithmetic

Perform math on durations without manual parsing. All accept string | number inputs and return milliseconds. Returns NaN if any input is invalid.

import { add, subtract, multiply, divide } from 'durate';

add('1h', '30m')              // 5_400_000
add('1h', '30m', '15s')      // 5_415_000
add(['1h', '30m'])            // 5_400_000
subtract('2d', '6h')          // 151_200_000
multiply('1h', 2)             // 7_200_000
multiply('1h', 2, 3)          // 21_600_000
divide('2h', 2)               // 3_600_000
divide('1d', 2, 3)            // 14_400_000

Comparison

Compare durations directly. Returns false if either value is NaN.

import { gt, lt, eq, gte, lte } from 'durate';

gt('1h', '30m')               // true
lt('30m', '1h')               // true
eq('60m', '1h')               // true
gte('1h', '1h')               // true
lte('30m', '1h')              // true

Options

ParseOptions

parse('5m', { unit: 's' })           // 300 (seconds instead of ms)
parse('bad', { strict: true })              // throws instead of NaN
parse('1mo', { safeForTimer: 'throw' })    // throws (exceeds setTimeout max)
parse('1mo', { safeForTimer: 'clamp' })    // returns MAX_TIMEOUT (2_147_483_647)

| Option | Type | Default | Description | | -------------- | ------------------------- | ----------- | --------------------------------------------------- | | unit | 'ms' \| 's' | 'ms' | Output unit | | strict | boolean | false | Throw on invalid input instead of NaN | | safeForTimer | 'throw' \| 'clamp' | undefined | Guard against setTimeout/setInterval overflow |

FormatOptions

format(3_600_000, { long: true })                // '1 hour'
format(5_425_000, { compound: true })            // '1h 30m 25s'
format(5_425_000, { compound: true, parts: 2 })  // '1h 30m'
format(5_400_000, { precision: 1 })              // '1.5h'
format(5_425_000, { template: 'HH:mm:ss' })     // '01:30:25'

| Option | Type | Default | Description | | ----------- | --------- | ----------- | ---------------------------------------------------- | | long | boolean | false | Use full words instead of short | | compound | boolean | false | Output multiple units ("1h 30m 25s") | | parts | number | all | Max number of units in compound output | | precision | number | 0 (round) | Decimal places for single-unit output | | template | string | undefined | Format string with tokens ("HH:mm:ss") |

Template tokens

| Token | Description | Example | | ----- | ----------- | ------- | | D | Days | 1 | | DD | Days (padded) | 01 | | H | Hours | 1 | | HH | Hours (padded) | 01 | | m | Minutes | 1 | | mm | Minutes (padded) | 01 | | s | Seconds | 1 | | ss | Seconds (padded) | 01 | | S | Milliseconds (remainder) | 500 | | SS | Centiseconds (ms÷10, padded) | 50 | | SSS | Milliseconds (zero-padded) | 005 | | [text] | Literal text | [h]h |

Values are remainder-based. If D is absent, H shows total hours.

Supported Units

| Unit | Short | Aliases | | ------------ | ----- | ----------------------------------------------- | | Years | y | yr, yrs, year, years | | Months | mo | mon, mons, month, months | | Weeks | w | week, weeks | | Days | d | day, days | | Hours | h | hr, hrs, hour, hours | | Minutes | m | min, mins, minute, minutes | | Seconds | s | sec, secs, second, seconds | | Milliseconds | ms | msec, msecs, millisecond, milliseconds |

All units are case-insensitive.

Timer Safety

setTimeout and setInterval use a 32-bit signed integer internally. Values above 2^31 - 1 (2,147,483,647 ms, ~24.85 days) overflow and the timer fires immediately. This means parse('1mo') or parse('1y') will silently break if passed directly to a timer.

Use the safeForTimer option to guard against this:

import { parse, MAX_TIMEOUT } from 'durate';

// Throws — 1 month exceeds the timer limit
parse('1mo', { safeForTimer: 'throw' })

// Clamps — returns MAX_TIMEOUT instead of overflowing
parse('1mo', { safeForTimer: 'clamp' })  // 2_147_483_647

// Works — 1 hour is well within range
setTimeout(callback, parse('1h', { safeForTimer: 'throw' }))

// Or check manually
const ms = parse('30d');
if (ms > MAX_TIMEOUT) { /* too large for setTimeout */ }

MAX_TIMEOUT is exported as a constant (2_147_483_647) for manual comparisons.

TypeScript

The DurationString type catches invalid strings at compile time:

import type { DurationString } from 'durate';

const ttl: DurationString = '15m';       // ok
const bad: DurationString = 'garbage';   // compile error

Migration from ms

- const ms = require('ms');
+ const ms = require('durate');
// everything else unchanged

Or with named exports:

- import ms from 'ms';
+ import { durate, parse, format, parseISO, formatISO, add, subtract, multiply, divide, gt, lt, eq, gte, lte } from 'durate';

parse and format signatures are identical. See the full migration guide for behavioral differences.

Browser

<script src="https://unpkg.com/durate"></script>
<script>
  durate('1h')  // 3_600_000
</script>

License

MIT