← BACK

pretty-ms

Convert milliseconds to a human readable string: `1337000000` → `15d 11h 23m 20s`

JavaScript ⭐ 1218

pretty-ms

Convert milliseconds to a human readable string: 1337000000 → 15d 11h 23m 20s

See parse-duration-ms for the inverse.

Install

npm install pretty-ms

Usage

import prettyMilliseconds from 'pretty-ms';

prettyMilliseconds(1337000000);
//=> '15d 11h 23m 20s'

prettyMilliseconds(1337000000n);
//=> '15d 11h 23m 20s'

prettyMilliseconds(1337);
//=> '1.3s'

prettyMilliseconds(133);
//=> '133ms'

// `compact` option
prettyMilliseconds(1337, {compact: true});
//=> '1s'

// `verbose` option
prettyMilliseconds(1335669000, {verbose: true});
//=> '15 days 11 hours 1 minute 9 seconds'

// `colonNotation` option
prettyMilliseconds(95500, {colonNotation: true});
//=> '1:35.5'

// `formatSubMilliseconds` option
prettyMilliseconds(100.400080, {formatSubMilliseconds: true})
//=> '100ms 400µs 80ns'

// `subSecondsAsDecimals` option
prettyMilliseconds(900, {subSecondsAsDecimals: true});
//=> '0.9s'

// Can be useful for time durations
prettyMilliseconds(new Date(2014, 0, 1, 10, 40) - new Date(2014, 0, 1, 10, 5))
//=> '35m'

API

prettyMilliseconds(milliseconds, options?)

milliseconds

Type: number | bigint

Milliseconds to humanize.

An integer (number or bigint) is exact at any size.

A fractional number is first rounded to 15 significant digits, the precision of a number, which removes float noise:

  • 0.57 * 100_000 (56999.99999999999) is 57s.
  • 999.9999999999999 (16 digits) is 1s, but 999.99999999999 (14 digits) is 999ms.

From 1e14 milliseconds (about 3,170 years) up, no digits are left for the fraction, so the duration is rounded to whole milliseconds, and from 1e15 (about 31,700 years) up, to the nearest 10 milliseconds.

options

Type: object

secondsDecimalDigits

Type: number
Default: 1

Number of digits to appear after the seconds decimal point.

Digits are floored, not rounded, so the seconds never round up into the next step: 1999ms is 1.9s, and at 0 digits it is 1s, never 2s. The flooring applies to the duration after it is read (see milliseconds for how a fractional number is read).

millisecondsDecimalDigits

Type: number
Default: 0

Number of digits to appear after the milliseconds decimal point.

The milliseconds are rounded, not floored, but they never round up to 1000ms, and a nonzero duration under a second never rounds down to 0ms: 999.6ms is 999ms, and 0.2ms is 1ms. This does not apply with formatSubMilliseconds, which floors instead.

Useful in combination with process.hrtime().

keepDecimalsOnWholeSeconds

Type: boolean
Default: false

Keep milliseconds on whole seconds: 13s → 13.0s.

Useful when you are showing a number of seconds spent on an operation and don't want the width of the output to change when hitting a whole number.

compact

Type: boolean
Default: false

Only show the first unit: 1h 10m → 1h.

Also ensures that millisecondsDecimalDigits and secondsDecimalDigits are both set to 0.

unitCount

Type: number
Default: Infinity

Number of units to show. Setting compact to true overrides this option. It is ignored with colonNotation.

verbose

Type: boolean
Default: false

Use full-length units: 5h 1m 45s → 5 hours 1 minute 45 seconds

separateMilliseconds

Type: boolean
Default: false

Show milliseconds separately. This means they won't be included in the decimal part of the seconds.

formatSubMilliseconds

Type: boolean
Default: false

Show microseconds and nanoseconds.

The values are floored to whole nanoseconds, so a duration under 1 nanosecond is 0ms.

colonNotation

Type: boolean
Default: false

Display time using colon notation: 5h 1m 45s → 5:01:45. Always shows time in at least minutes: 1s → 0:01, or in at least hours with hideSeconds: 1m → 0:01.

Useful when you want to display time without the time units, similar to a digital watch.

Setting colonNotation to true overrides the following options to false:

  • compact
  • formatSubMilliseconds
  • separateMilliseconds
  • verbose

Days after a year are padded to 3 digits to keep the width: 1:005:00:00:00.

It also ignores unitCount, as dropping a field would change what the remaining fields mean: 1:01:01 would become 1:01, which reads as 1 minute.

hideYear

Type: boolean
Default: false

Hides the year and shows the hidden year additionally as days (365 per year): 1y 3d 5h 1m 45s → 368d 5h 1m 45s.

hideYearAndDays

Type: boolean
Default: false

Hides the year and days and shows the hidden values additionally as hours: 1y 3d 5h 1m 45s → 8837h 1m 45s.

hideSeconds

Type: boolean
Default: false

Hides the seconds: 1y 3d 5h 1m 45s → 1y 3d 5h 1m.

A duration under a minute has no coarser unit, so it keeps its seconds rather than showing nothing. With colonNotation, the hours are always shown, so the fields read as h:mm: 60000 → 0:01, and 45000 → 0:00:45.

subSecondsAsDecimals

Type: boolean
Default: false

Show sub-second values as decimal seconds: 900ms → 0.9s.

Useful for progress indicators where you want consistent unit format to prevent flickering.

Also floored, so 999ms is 0.9s.

A duration too small for the seconds field to show, like 50ms at the default secondsDecimalDigits of 1, stays in milliseconds rather than showing as zero. With compact, the seconds have no decimals, so a duration under a second stays in milliseconds.

FAQ

Why doesn't this package support months?

This package formats time durations, not calendar dates. Months (28-31 days) have variable lengths, making duration calculations ambiguous. Years are shown as a fixed 365 days, so they do not account for leap years. Use the hideYear option to show days as the largest unit, since days are always exactly 24 hours. For calendar-based formatting, use Temporal API or a date library like date-fns.

Why doesn't the formatted difference of two values match the formatted values?

prettyMilliseconds(3670);        //=> '3.6s'
prettyMilliseconds(5230);        //=> '5.2s'
prettyMilliseconds(5230 - 3670); //=> '1.5s' // Not '1.6s'

This is inherent to displaying rounded numbers, the same reason rounded percentages don't always add up to 100%. Values are rounded independently, and rounding does not distribute over subtraction. prettyMilliseconds(5230 - 3670) correctly represents the true difference; it just won't always match subtracting the two rounded strings by eye.

Related