pax_global_header00006660000000000000000000000064142473740710014523gustar00rootroot0000000000000052 comment=73389247d677dd83587b43bed255b6d38b4b65a7 pretty-ms-8.0.0/000077500000000000000000000000001424737407100134745ustar00rootroot00000000000000pretty-ms-8.0.0/.editorconfig000066400000000000000000000002571424737407100161550ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 pretty-ms-8.0.0/.gitattributes000066400000000000000000000000231424737407100163620ustar00rootroot00000000000000* text=auto eol=lf pretty-ms-8.0.0/.github/000077500000000000000000000000001424737407100150345ustar00rootroot00000000000000pretty-ms-8.0.0/.github/workflows/000077500000000000000000000000001424737407100170715ustar00rootroot00000000000000pretty-ms-8.0.0/.github/workflows/main.yml000066400000000000000000000006641424737407100205460ustar00rootroot00000000000000name: CI on: - push - pull_request jobs: test: name: Node.js ${{ matrix.node-version }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: node-version: - 18 - 16 - 14 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm test pretty-ms-8.0.0/.gitignore000066400000000000000000000000271424737407100154630ustar00rootroot00000000000000node_modules yarn.lock pretty-ms-8.0.0/.npmrc000066400000000000000000000000231424737407100146070ustar00rootroot00000000000000package-lock=false pretty-ms-8.0.0/index.d.ts000066400000000000000000000053731424737407100154050ustar00rootroot00000000000000export interface Options { /** Number of digits to appear after the seconds decimal point. @default 1 */ readonly secondsDecimalDigits?: number; /** Number of digits to appear after the milliseconds decimal point. Useful in combination with [`process.hrtime()`](https://nodejs.org/api/process.html#process_process_hrtime). @default 0 */ readonly millisecondsDecimalDigits?: number; /** 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. @default false */ readonly keepDecimalsOnWholeSeconds?: boolean; /** Only show the first unit: `1h 10m` → `1h`. Also ensures that `millisecondsDecimalDigits` and `secondsDecimalDigits` are both set to `0`. @default false */ readonly compact?: boolean; /** Number of units to show. Setting `compact` to `true` overrides this option. @default Infinity */ readonly unitCount?: number; /** Use full-length units: `5h 1m 45s` → `5 hours 1 minute 45 seconds`. @default false */ readonly verbose?: boolean; /** Show milliseconds separately. This means they won't be included in the decimal part of the seconds. @default false */ readonly separateMilliseconds?: boolean; /** Show microseconds and nanoseconds. @default false */ readonly formatSubMilliseconds?: boolean; /** Display time using colon notation: `5h 1m 45s` → `5:01:45`. Always shows time in at least minutes: `1s` → `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` @default false */ readonly colonNotation?: boolean; } /** Convert milliseconds to a human readable string: `1337000000` → `15d 11h 23m 20s`. @param milliseconds - Milliseconds to humanize. @example ``` import prettyMilliseconds from 'pretty-ms'; prettyMilliseconds(1337000000); //=> '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' // Can be useful for time durations prettyMilliseconds(new Date(2014, 0, 1, 10, 40) - new Date(2014, 0, 1, 10, 5)) //=> '35m' ``` */ export default function prettyMilliseconds( milliseconds: number, options?: Options ): string; pretty-ms-8.0.0/index.js000066400000000000000000000072121424737407100151430ustar00rootroot00000000000000import parseMilliseconds from 'parse-ms'; const pluralize = (word, count) => count === 1 ? word : `${word}s`; const SECOND_ROUNDING_EPSILON = 0.000_000_1; export default function prettyMilliseconds(milliseconds, options = {}) { if (!Number.isFinite(milliseconds)) { throw new TypeError('Expected a finite number'); } if (options.colonNotation) { options.compact = false; options.formatSubMilliseconds = false; options.separateMilliseconds = false; options.verbose = false; } if (options.compact) { options.secondsDecimalDigits = 0; options.millisecondsDecimalDigits = 0; } const result = []; const floorDecimals = (value, decimalDigits) => { const flooredInterimValue = Math.floor((value * (10 ** decimalDigits)) + SECOND_ROUNDING_EPSILON); const flooredValue = Math.round(flooredInterimValue) / (10 ** decimalDigits); return flooredValue.toFixed(decimalDigits); }; const add = (value, long, short, valueString) => { if ((result.length === 0 || !options.colonNotation) && value === 0 && !(options.colonNotation && short === 'm')) { return; } valueString = (valueString || value || '0').toString(); let prefix; let suffix; if (options.colonNotation) { prefix = result.length > 0 ? ':' : ''; suffix = ''; const wholeDigits = valueString.includes('.') ? valueString.split('.')[0].length : valueString.length; const minLength = result.length > 0 ? 2 : 1; valueString = '0'.repeat(Math.max(0, minLength - wholeDigits)) + valueString; } else { prefix = ''; suffix = options.verbose ? ' ' + pluralize(long, value) : short; } result.push(prefix + valueString + suffix); }; const parsed = parseMilliseconds(milliseconds); add(Math.trunc(parsed.days / 365), 'year', 'y'); add(parsed.days % 365, 'day', 'd'); add(parsed.hours, 'hour', 'h'); add(parsed.minutes, 'minute', 'm'); if ( options.separateMilliseconds || options.formatSubMilliseconds || (!options.colonNotation && milliseconds < 1000) ) { add(parsed.seconds, 'second', 's'); if (options.formatSubMilliseconds) { add(parsed.milliseconds, 'millisecond', 'ms'); add(parsed.microseconds, 'microsecond', 'µs'); add(parsed.nanoseconds, 'nanosecond', 'ns'); } else { const millisecondsAndBelow = parsed.milliseconds + (parsed.microseconds / 1000) + (parsed.nanoseconds / 1e6); const millisecondsDecimalDigits = typeof options.millisecondsDecimalDigits === 'number' ? options.millisecondsDecimalDigits : 0; const roundedMiliseconds = millisecondsAndBelow >= 1 ? Math.round(millisecondsAndBelow) : Math.ceil(millisecondsAndBelow); const millisecondsString = millisecondsDecimalDigits ? millisecondsAndBelow.toFixed(millisecondsDecimalDigits) : roundedMiliseconds; add( Number.parseFloat(millisecondsString), 'millisecond', 'ms', millisecondsString, ); } } else { const seconds = (milliseconds / 1000) % 60; const secondsDecimalDigits = typeof options.secondsDecimalDigits === 'number' ? options.secondsDecimalDigits : 1; const secondsFixed = floorDecimals(seconds, secondsDecimalDigits); const secondsString = options.keepDecimalsOnWholeSeconds ? secondsFixed : secondsFixed.replace(/\.0+$/, ''); add(Number.parseFloat(secondsString), 'second', 's', secondsString); } if (result.length === 0) { return '0' + (options.verbose ? ' milliseconds' : 'ms'); } if (options.compact) { return result[0]; } if (typeof options.unitCount === 'number') { const separator = options.colonNotation ? '' : ' '; return result.slice(0, Math.max(options.unitCount, 1)).join(separator); } return options.colonNotation ? result.join('') : result.join(' '); } pretty-ms-8.0.0/index.test-d.ts000066400000000000000000000015441424737407100163560ustar00rootroot00000000000000import {expectType} from 'tsd'; import prettyMilliseconds from './index.js'; expectType(prettyMilliseconds(1_335_669_000)); expectType(prettyMilliseconds(1_335_669_000, {secondsDecimalDigits: 1})); expectType( prettyMilliseconds(1_335_669_000, {millisecondsDecimalDigits: 2}), ); expectType( prettyMilliseconds(1_335_669_000, {keepDecimalsOnWholeSeconds: true}), ); expectType(prettyMilliseconds(1337, {compact: true})); expectType(prettyMilliseconds(1_335_669_000, {unitCount: 2})); expectType(prettyMilliseconds(1_335_669_000, {verbose: true})); expectType( prettyMilliseconds(1_335_669_000, {separateMilliseconds: true}), ); expectType( prettyMilliseconds(1_335_669_000, {formatSubMilliseconds: true}), ); expectType( prettyMilliseconds(1_335_669_000, {colonNotation: true}), ); pretty-ms-8.0.0/license000066400000000000000000000021351424737407100150420ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pretty-ms-8.0.0/package.json000066400000000000000000000016411424737407100157640ustar00rootroot00000000000000{ "name": "pretty-ms", "version": "8.0.0", "description": "Convert milliseconds to a human readable string: `1337000000` → `15d 11h 23m 20s`", "license": "MIT", "repository": "sindresorhus/pretty-ms", "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, "type": "module", "exports": "./index.js", "types": "./index.d.ts", "engines": { "node": ">=14.16" }, "scripts": { "test": "xo && ava && tsd" }, "files": [ "index.js", "index.d.ts" ], "keywords": [ "pretty", "prettify", "human", "humanize", "humanized", "readable", "time", "ms", "milliseconds", "duration", "period", "range", "text", "string", "number", "hrtime" ], "dependencies": { "parse-ms": "^3.0.0" }, "devDependencies": { "ava": "^4.3.0", "tsd": "^0.20.0", "xo": "^0.49.0" } } pretty-ms-8.0.0/readme.md000066400000000000000000000062001424737407100152510ustar00rootroot00000000000000# pretty-ms > Convert milliseconds to a human readable string: `1337000000` → `15d 11h 23m 20s` ## Install ```sh npm install pretty-ms ``` ## Usage ```js import prettyMilliseconds from 'pretty-ms'; prettyMilliseconds(1337000000); //=> '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' // 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` Milliseconds to humanize. #### options Type: `object` ##### secondsDecimalDigits Type: `number`\ Default: `1` Number of digits to appear after the seconds decimal point. ##### millisecondsDecimalDigits Type: `number`\ Default: `0` Number of digits to appear after the milliseconds decimal point. Useful in combination with [`process.hrtime()`](https://nodejs.org/api/process.html#process_process_hrtime_time). ##### 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. ##### 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. ##### 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` 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` ## Related - [pretty-ms-cli](https://github.com/sindresorhus/pretty-ms-cli) - CLI for this module - [parse-ms](https://github.com/sindresorhus/parse-ms) - Parse milliseconds into an object - [to-milliseconds](https://github.com/sindresorhus/to-milliseconds) - Convert an object of time properties to milliseconds - [pretty-bytes](https://github.com/sindresorhus/pretty-bytes) - Convert bytes to a human readable string pretty-ms-8.0.0/test.js000066400000000000000000000336501424737407100150200ustar00rootroot00000000000000import test from 'ava'; import prettyMilliseconds from './index.js'; test('prettify milliseconds', t => { t.is(prettyMilliseconds(0), '0ms'); t.is(prettyMilliseconds(0.1), '1ms'); t.is(prettyMilliseconds(1), '1ms'); t.is(prettyMilliseconds(999), '999ms'); t.is(prettyMilliseconds(1000), '1s'); t.is(prettyMilliseconds(1000 + 400), '1.4s'); t.is(prettyMilliseconds((1000 * 2) + 400), '2.4s'); t.is(prettyMilliseconds(1000 * 55), '55s'); t.is(prettyMilliseconds(1000 * 67), '1m 7s'); t.is(prettyMilliseconds(1000 * 60 * 5), '5m'); t.is(prettyMilliseconds(1000 * 60 * 67), '1h 7m'); t.is(prettyMilliseconds(1000 * 60 * 60 * 12), '12h'); t.is(prettyMilliseconds(1000 * 60 * 60 * 40), '1d 16h'); t.is(prettyMilliseconds(1000 * 60 * 60 * 999), '41d 15h'); t.is(prettyMilliseconds(1000 * 60 * 60 * 24 * 465), '1y 100d'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465), '1y 154d 6h'); t.is(prettyMilliseconds(119_999), '1m 59.9s'); t.is(prettyMilliseconds(120_000), '2m'); }); test('have a compact option', t => { t.is(prettyMilliseconds(1000 + 4, {compact: true}), '1s'); t.is(prettyMilliseconds(1000 * 60 * 60 * 999, {compact: true}), '41d'); t.is(prettyMilliseconds(1000 * 60 * 60 * 24 * 465, {compact: true}), '1y'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {compact: true}), '1y'); }); test('have a unitCount option', t => { t.is(prettyMilliseconds(1000 * 60, {unitCount: 0}), '1m'); t.is(prettyMilliseconds(1000 * 60, {unitCount: 1}), '1m'); t.is(prettyMilliseconds(1000 * 60 * 67, {unitCount: 1}), '1h'); t.is(prettyMilliseconds(1000 * 60 * 67, {unitCount: 2}), '1h 7m'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {unitCount: 1}), '1y'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {unitCount: 2}), '1y 154d'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {unitCount: 3}), '1y 154d 6h'); }); test('have a secondsDecimalDigits option', t => { t.is(prettyMilliseconds(10_000), '10s'); t.is(prettyMilliseconds(33_333), '33.3s'); t.is(prettyMilliseconds(999, {secondsDecimalDigits: 0}), '999ms'); t.is(prettyMilliseconds(1000, {secondsDecimalDigits: 0}), '1s'); t.is(prettyMilliseconds(1999, {secondsDecimalDigits: 0}), '1s'); t.is(prettyMilliseconds(2000, {secondsDecimalDigits: 0}), '2s'); t.is(prettyMilliseconds(33_333, {secondsDecimalDigits: 0}), '33s'); t.is(prettyMilliseconds(33_333, {secondsDecimalDigits: 4}), '33.3330s'); }); test('have a millisecondsDecimalDigits option', t => { t.is(prettyMilliseconds(33.333), '33ms'); t.is(prettyMilliseconds(33.333, {millisecondsDecimalDigits: 0}), '33ms'); t.is(prettyMilliseconds(33.333, {millisecondsDecimalDigits: 4}), '33.3330ms'); }); test('have a keepDecimalsOnWholeSeconds option', t => { t.is(prettyMilliseconds(1000 * 33, {secondsDecimalDigits: 2, keepDecimalsOnWholeSeconds: true}), '33.00s'); t.is(prettyMilliseconds(1000 * 33.000_04, {secondsDecimalDigits: 2, keepDecimalsOnWholeSeconds: true}), '33.00s'); }); test('have a verbose option', t => { const fn = milliseconds => prettyMilliseconds(milliseconds, {verbose: true}); t.is(fn(0), '0 milliseconds'); t.is(fn(0.1), '1 millisecond'); t.is(fn(1), '1 millisecond'); t.is(fn(1000), '1 second'); t.is(fn(1000 + 400), '1.4 seconds'); t.is(fn((1000 * 2) + 400), '2.4 seconds'); t.is(fn(1000 * 5), '5 seconds'); t.is(fn(1000 * 55), '55 seconds'); t.is(fn(1000 * 67), '1 minute 7 seconds'); t.is(fn(1000 * 60 * 5), '5 minutes'); t.is(fn(1000 * 60 * 67), '1 hour 7 minutes'); t.is(fn(1000 * 60 * 60 * 12), '12 hours'); t.is(fn(1000 * 60 * 60 * 40), '1 day 16 hours'); t.is(fn(1000 * 60 * 60 * 999), '41 days 15 hours'); t.is(fn(1000 * 60 * 60 * 24 * 465), '1 year 100 days'); t.is(fn(1000 * 60 * 67 * 24 * 465), '1 year 154 days 6 hours'); }); test('have a separateMilliseconds option', t => { t.is(prettyMilliseconds(1100, {separateMilliseconds: false}), '1.1s'); t.is(prettyMilliseconds(1100, {separateMilliseconds: true}), '1s 100ms'); }); test('have a formatSubMilliseconds option', t => { t.is(prettyMilliseconds(0.4, {formatSubMilliseconds: true}), '400µs'); t.is(prettyMilliseconds(0.123_571, {formatSubMilliseconds: true}), '123µs 571ns'); t.is(prettyMilliseconds(0.123_456_789, {formatSubMilliseconds: true}), '123µs 456ns'); t.is( prettyMilliseconds((60 * 60 * 1000) + (23 * 1000) + 433 + 0.123_456, { formatSubMilliseconds: true, }), '1h 23s 433ms 123µs 456ns', ); }); test('work with verbose and compact options', t => { const fn = milliseconds => prettyMilliseconds(milliseconds, { verbose: true, compact: true, }); t.is(fn(1000), '1 second'); t.is(fn(1000 + 400), '1 second'); t.is(fn((1000 * 2) + 400), '2 seconds'); t.is(fn(1000 * 5), '5 seconds'); t.is(fn(1000 * 55), '55 seconds'); t.is(fn(1000 * 67), '1 minute'); t.is(fn(1000 * 60 * 5), '5 minutes'); t.is(fn(1000 * 60 * 67), '1 hour'); t.is(fn(1000 * 60 * 60 * 12), '12 hours'); t.is(fn(1000 * 60 * 60 * 40), '1 day'); t.is(fn(1000 * 60 * 60 * 999), '41 days'); t.is(fn(1000 * 60 * 60 * 24 * 465), '1 year'); t.is(fn(1000 * 60 * 67 * 24 * 750), '2 years'); }); test('work with verbose and unitCount options', t => { t.is(prettyMilliseconds(1000 * 60, {verbose: true, unitCount: 1}), '1 minute'); t.is(prettyMilliseconds(1000 * 60 * 67, {verbose: true, unitCount: 1}), '1 hour'); t.is(prettyMilliseconds(1000 * 60 * 67, {verbose: true, unitCount: 2}), '1 hour 7 minutes'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, unitCount: 1}), '1 year'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, unitCount: 2}), '1 year 154 days'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, unitCount: 3}), '1 year 154 days 6 hours'); }); test('work with verbose and secondsDecimalDigits options', t => { const fn = milliseconds => prettyMilliseconds(milliseconds, { verbose: true, secondsDecimalDigits: 4, }); t.is(fn(1000), '1 second'); t.is(fn(1000 + 400), '1.4000 seconds'); t.is(fn((1000 * 2) + 400), '2.4000 seconds'); t.is(fn((1000 * 5) + 254), '5.2540 seconds'); t.is(fn(33_333), '33.3330 seconds'); }); test('work with verbose and millisecondsDecimalDigits options', t => { const fn = milliseconds => prettyMilliseconds(milliseconds, { verbose: true, millisecondsDecimalDigits: 4, }); t.is(fn(1), '1.0000 millisecond'); t.is(fn(1 + 0.4), '1.4000 milliseconds'); t.is(fn((1 * 2) + 0.4), '2.4000 milliseconds'); t.is(fn((1 * 5) + 0.254), '5.2540 milliseconds'); t.is(fn(33.333), '33.3330 milliseconds'); }); test('work with verbose and formatSubMilliseconds options', t => { t.is( prettyMilliseconds(0.4, {formatSubMilliseconds: true, verbose: true}), '400 microseconds', ); t.is( prettyMilliseconds(0.123_571, { formatSubMilliseconds: true, verbose: true, }), '123 microseconds 571 nanoseconds', ); t.is( prettyMilliseconds(0.123_456_789, { formatSubMilliseconds: true, verbose: true, }), '123 microseconds 456 nanoseconds', ); t.is( prettyMilliseconds(0.001, {formatSubMilliseconds: true, verbose: true}), '1 microsecond', ); }); test('compact option overrides unitCount option', t => { t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, compact: true, unitCount: 1}), '1 year'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, compact: true, unitCount: 2}), '1 year'); t.is(prettyMilliseconds(1000 * 60 * 67 * 24 * 465, {verbose: true, compact: true, unitCount: 3}), '1 year'); }); test('work with separateMilliseconds and formatSubMilliseconds options', t => { t.is( prettyMilliseconds(1010.340_067, { separateMilliseconds: true, formatSubMilliseconds: true, }), '1s 10ms 340µs 67ns', ); t.is( prettyMilliseconds((60 * 1000) + 34 + 0.000_005, { separateMilliseconds: true, formatSubMilliseconds: true, }), '1m 34ms 5ns', ); }); test('throw on invalid', t => { t.throws(() => { prettyMilliseconds('foo'); }); t.throws(() => { prettyMilliseconds(Number.NaN); }); t.throws(() => { prettyMilliseconds(Number.POSITIVE_INFINITY); }); }); test('properly rounds milliseconds with secondsDecimalDigits', t => { const fn = milliseconds => prettyMilliseconds(milliseconds, { verbose: true, secondsDecimalDigits: 0, }); t.is(fn(3 * 60 * 1000), '3 minutes'); t.is(fn((3 * 60 * 1000) - 1), '2 minutes 59 seconds'); t.is(fn(365 * 24 * 3600 * 1e3), '1 year'); t.is(fn((365 * 24 * 3600 * 1e3) - 1), '364 days 23 hours 59 minutes 59 seconds'); t.is(fn(24 * 3600 * 1e3), '1 day'); t.is(fn((24 * 3600 * 1e3) - 1), '23 hours 59 minutes 59 seconds'); t.is(fn(3600 * 1e3), '1 hour'); t.is(fn((3600 * 1e3) - 1), '59 minutes 59 seconds'); t.is(fn(2 * 3600 * 1e3), '2 hours'); t.is(fn((2 * 3600 * 1e3) - 1), '1 hour 59 minutes 59 seconds'); }); test('`colonNotation` option', t => { // Default formats t.is(prettyMilliseconds(1000, {colonNotation: true}), '0:01'); t.is(prettyMilliseconds(1543, {colonNotation: true}), '0:01.5'); t.is(prettyMilliseconds(1000 * 60, {colonNotation: true}), '1:00'); t.is(prettyMilliseconds(1000 * 90, {colonNotation: true}), '1:30'); t.is(prettyMilliseconds(95_543, {colonNotation: true}), '1:35.5'); t.is(prettyMilliseconds((1000 * 60 * 10) + 543, {colonNotation: true}), '10:00.5'); t.is(prettyMilliseconds((1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true}), '59:59.5'); t.is(prettyMilliseconds((1000 * 60 * 60 * 15) + (1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true}), '15:59:59.5'); // Together with `secondsDecimalDigits` t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 0}), '0:00'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 1}), '0:00.9'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 2}), '0:00.99'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 3}), '0:00.999'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 0}), '0:01'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 1}), '0:01'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 2}), '0:01'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 3}), '0:01'); t.is(prettyMilliseconds(1001, {colonNotation: true, secondsDecimalDigits: 0}), '0:01'); t.is(prettyMilliseconds(1001, {colonNotation: true, secondsDecimalDigits: 1}), '0:01'); t.is(prettyMilliseconds(1001, {colonNotation: true, secondsDecimalDigits: 2}), '0:01'); t.is(prettyMilliseconds(1001, {colonNotation: true, secondsDecimalDigits: 3}), '0:01.001'); t.is(prettyMilliseconds(1543, {colonNotation: true, secondsDecimalDigits: 0}), '0:01'); t.is(prettyMilliseconds(1543, {colonNotation: true, secondsDecimalDigits: 1}), '0:01.5'); t.is(prettyMilliseconds(1543, {colonNotation: true, secondsDecimalDigits: 2}), '0:01.54'); t.is(prettyMilliseconds(1543, {colonNotation: true, secondsDecimalDigits: 3}), '0:01.543'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 0}), '1:35'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 1}), '1:35.5'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 2}), '1:35.54'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 3}), '1:35.543'); t.is(prettyMilliseconds((1000 * 60 * 10) + 543, {colonNotation: true, secondsDecimalDigits: 3}), '10:00.543'); t.is(prettyMilliseconds((1000 * 60 * 60 * 15) + (1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true, secondsDecimalDigits: 3}), '15:59:59.543'); // Together with `keepDecimalsOnWholeSeconds` t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 0, keepDecimalsOnWholeSeconds: true}), '0:00'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 1, keepDecimalsOnWholeSeconds: true}), '0:00.9'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 2, keepDecimalsOnWholeSeconds: true}), '0:00.99'); t.is(prettyMilliseconds(999, {colonNotation: true, secondsDecimalDigits: 3, keepDecimalsOnWholeSeconds: true}), '0:00.999'); t.is(prettyMilliseconds(1000, {colonNotation: true, keepDecimalsOnWholeSeconds: true}), '0:01.0'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 0, keepDecimalsOnWholeSeconds: true}), '0:01'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 1, keepDecimalsOnWholeSeconds: true}), '0:01.0'); t.is(prettyMilliseconds(1000, {colonNotation: true, secondsDecimalDigits: 3, keepDecimalsOnWholeSeconds: true}), '0:01.000'); t.is(prettyMilliseconds(1000 * 90, {colonNotation: true, keepDecimalsOnWholeSeconds: true}), '1:30.0'); t.is(prettyMilliseconds(1000 * 90, {colonNotation: true, secondsDecimalDigits: 3, keepDecimalsOnWholeSeconds: true}), '1:30.000'); t.is(prettyMilliseconds(1000 * 60 * 10, {colonNotation: true, secondsDecimalDigits: 3, keepDecimalsOnWholeSeconds: true}), '10:00.000'); // Together with `unitCount` t.is(prettyMilliseconds(1000 * 90, {colonNotation: true, secondsDecimalDigits: 0, unitCount: 1}), '1'); t.is(prettyMilliseconds(1000 * 90, {colonNotation: true, secondsDecimalDigits: 0, unitCount: 2}), '1:30'); t.is(prettyMilliseconds(1000 * 60 * 90, {colonNotation: true, secondsDecimalDigits: 0, unitCount: 3}), '1:30:00'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 1, unitCount: 1}), '1'); t.is(prettyMilliseconds(95_543, {colonNotation: true, secondsDecimalDigits: 1, unitCount: 2}), '1:35.5'); t.is(prettyMilliseconds(95_543 + (1000 * 60 * 60), {colonNotation: true, secondsDecimalDigits: 1, unitCount: 3}), '1:01:35.5'); // Make sure incompatible options fall back to `colonNotation` t.is(prettyMilliseconds((1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true, formatSubMilliseconds: true}), '59:59.5'); t.is(prettyMilliseconds((1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true, separateMilliseconds: true}), '59:59.5'); t.is(prettyMilliseconds((1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true, verbose: true}), '59:59.5'); t.is(prettyMilliseconds((1000 * 60 * 59) + (1000 * 59) + 543, {colonNotation: true, compact: true}), '59:59.5'); });