diff --git a/index.js b/index.js index c4498bc..4832ad3 100644 --- a/index.js +++ b/index.js @@ -15,6 +15,7 @@ var y = d * 365.25; * Options: * * - `long` verbose formatting [false] + * - `decimal` decimal place [0], maximum 3 decimal place * * @param {String|Number} val * @param {Object} [options] @@ -25,11 +26,12 @@ var y = d * 365.25; module.exports = function(val, options) { options = options || {}; + var decimal = options.decimal ? Math.min(options.decimal, 3) : 0; var type = typeof val; if (type === 'string' && val.length > 0) { return parse(val); } else if (type === 'number' && isFinite(val)) { - return options.long ? fmtLong(val) : fmtShort(val); + return options.long ? fmtLong(val, decimal) : fmtShort(val, decimal); } throw new Error( 'val is not a non-empty string or a valid number. val=' + @@ -106,23 +108,25 @@ function parse(str) { * Short format for `ms`. * * @param {Number} ms + * @param {Number} demical * @return {String} * @api private */ -function fmtShort(ms) { +function fmtShort(ms, decimal) { var msAbs = Math.abs(ms); + var base = Math.pow(10, decimal); if (msAbs >= d) { - return Math.round(ms / d) + 'd'; + return Math.round((ms / d) * base) / base + 'd'; } if (msAbs >= h) { - return Math.round(ms / h) + 'h'; + return Math.round((ms / h) * base) / base + 'h'; } if (msAbs >= m) { - return Math.round(ms / m) + 'm'; + return Math.round((ms / m) * base) / base + 'm'; } if (msAbs >= s) { - return Math.round(ms / s) + 's'; + return Math.round((ms / s) * base) / base + 's'; } return ms + 'ms'; } @@ -131,23 +135,24 @@ function fmtShort(ms) { * Long format for `ms`. * * @param {Number} ms + * @param {Number} demical * @return {String} * @api private */ -function fmtLong(ms) { +function fmtLong(ms, demical) { var msAbs = Math.abs(ms); if (msAbs >= d) { - return plural(ms, msAbs, d, 'day'); + return plural(ms, msAbs, d, 'day', demical); } if (msAbs >= h) { - return plural(ms, msAbs, h, 'hour'); + return plural(ms, msAbs, h, 'hour', demical); } if (msAbs >= m) { - return plural(ms, msAbs, m, 'minute'); + return plural(ms, msAbs, m, 'minute', demical); } if (msAbs >= s) { - return plural(ms, msAbs, s, 'second'); + return plural(ms, msAbs, s, 'second', demical); } return ms + ' ms'; } @@ -156,7 +161,10 @@ function fmtLong(ms) { * Pluralization helper. */ -function plural(ms, msAbs, n, name) { +function plural(ms, msAbs, n, name, demical) { var isPlural = msAbs >= n * 1.5; - return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); + var base = Math.pow(10, demical); + return ( + Math.round((ms / n) * base) / base + ' ' + name + (isPlural ? 's' : '') + ); } diff --git a/readme.md b/readme.md index 9a1996b..700f9f8 100644 --- a/readme.md +++ b/readme.md @@ -40,6 +40,16 @@ ms(-3 * 60000, { long: true }) // "-3 minutes" ms(ms('10 hours'), { long: true }) // "10 hours" ``` +### Round to decimal place + +```js +ms(60000, { decimal: 1 }) // "1m" +ms(66000, { decimal: 1 }) // "1.1m" +ms(-3 * 66000, { long: true, decimal: 1 }) // "-3.3 minutes" +ms(234234234, { decimal: 2 }) // "2.71m" +ms(ms('10.5 hours'), { long: true, decimal: 1 }) // "10.5 hours" +``` + ## Features - Works both in [Node.js](https://nodejs.org) and in the browser diff --git a/tests.js b/tests.js index 1d0d663..0ba7dfe 100644 --- a/tests.js +++ b/tests.js @@ -246,6 +246,173 @@ describe('ms(number)', function() { }); }); +// numbers with decimal + +describe('ms(number, { long: true, decimal: n })', function() { + it('should not throw an error', function() { + expect(function() { + ms(500, { long: true, decimal: 1 }); + }).to.not.throwError(); + }); + + it('should support milliseconds', function() { + expect(ms(500, { long: true, decimal: 1 })).to.be('500 ms'); + + expect(ms(-500, { long: true, decimal: 1 })).to.be('-500 ms'); + }); + + it('should support seconds', function() { + expect(ms(1000, { long: true, decimal: 1 })).to.be('1 second'); + expect(ms(1200, { long: true, decimal: 1 })).to.be('1.2 second'); + expect(ms(1234, { long: true, decimal: 2 })).to.be('1.23 second'); + expect(ms(10000, { long: true, decimal: 1 })).to.be('10 seconds'); + + expect(ms(-1000, { long: true, decimal: 1 })).to.be('-1 second'); + expect(ms(-1200, { long: true, decimal: 1 })).to.be('-1.2 second'); + expect(ms(-10000, { long: true, decimal: 1 })).to.be('-10 seconds'); + }); + + it('should support minutes', function() { + expect(ms(60 * 1000, { long: true, decimal: 1 })).to.be('1 minute'); + expect(ms(60 * 1200, { long: true, decimal: 1 })).to.be('1.2 minute'); + expect(ms(60 * 10000, { long: true, decimal: 1 })).to.be('10 minutes'); + + expect(ms(-1 * 60 * 1000, { long: true, decimal: 1 })).to.be('-1 minute'); + expect(ms(-1 * 60 * 1200, { long: true, decimal: 1 })).to.be('-1.2 minute'); + expect(ms(-1 * 60 * 10000, { long: true, decimal: 1 })).to.be( + '-10 minutes' + ); + }); + + it('should support hours', function() { + expect(ms(60 * 60 * 1000, { long: true, decimal: 1 })).to.be('1 hour'); + expect(ms(60 * 60 * 1200, { long: true, decimal: 1 })).to.be('1.2 hour'); + expect(ms(60 * 60 * 10000, { long: true, decimal: 1 })).to.be('10 hours'); + + expect(ms(-1 * 60 * 60 * 1000, { long: true, decimal: 1 })).to.be( + '-1 hour' + ); + expect(ms(-1 * 60 * 60 * 1200, { long: true, decimal: 1 })).to.be( + '-1.2 hour' + ); + expect(ms(-1 * 60 * 60 * 10000, { long: true, decimal: 1 })).to.be( + '-10 hours' + ); + }); + + it('should support days', function() { + expect(ms(24 * 60 * 60 * 1000, { long: true, decimal: 1 })).to.be('1 day'); + expect(ms(24 * 60 * 60 * 1200, { long: true, decimal: 1 })).to.be( + '1.2 day' + ); + expect(ms(24 * 60 * 60 * 10000, { long: true, decimal: 1 })).to.be( + '10 days' + ); + + expect(ms(-1 * 24 * 60 * 60 * 1000, { long: true, decimal: 1 })).to.be( + '-1 day' + ); + expect(ms(-1 * 24 * 60 * 60 * 1200, { long: true, decimal: 1 })).to.be( + '-1.2 day' + ); + expect(ms(-1 * 24 * 60 * 60 * 10000, { long: true, decimal: 1 })).to.be( + '-10 days' + ); + }); + + it('should round with 2 decimal place', function() { + expect(ms(234234234, { long: true, decimal: 2 })).to.be('2.71 days'); + + expect(ms(-234234234, { long: true, decimal: 2 })).to.be('-2.71 days'); + }); + + it('should round with up to 3 decimal place', function() { + expect(ms(234234234, { long: true, decimal: 3 })).to.be('2.711 days'); + expect(ms(234234234, { long: true, decimal: 10 })).to.be('2.711 days'); + + expect(ms(-234234234, { long: true, decimal: 3 })).to.be('-2.711 days'); + expect(ms(-234234234, { long: true, decimal: 10 })).to.be('-2.711 days'); + + expect(ms(ms('10.54321 hours'), { long: true, decimal: 1 })).to.be( + '10.5 hours' + ); + expect(ms(-3 * 66121, { long: true, decimal: 1 })).to.be('-3.3 minutes'); + }); +}); + +// numbers + +describe('ms(number, { decimal: n })', function() { + it('should not throw an error', function() { + expect(function() { + ms(500, { decimal: 1 }); + }).to.not.throwError(); + }); + + it('should support milliseconds', function() { + expect(ms(500, { decimal: 1 })).to.be('500ms'); + + expect(ms(-500, { decimal: 1 })).to.be('-500ms'); + }); + + it('should support seconds', function() { + expect(ms(1000, { decimal: 1 })).to.be('1s'); + expect(ms(1200, { decimal: 1 })).to.be('1.2s'); + expect(ms(10000, { decimal: 1 })).to.be('10s'); + + expect(ms(-1000, { decimal: 1 })).to.be('-1s'); + expect(ms(-1200, { decimal: 1 })).to.be('-1.2s'); + expect(ms(-10000, { decimal: 1 })).to.be('-10s'); + }); + + it('should support minutes', function() { + expect(ms(60 * 1000, { decimal: 1 })).to.be('1m'); + expect(ms(60 * 1200, { decimal: 1 })).to.be('1.2m'); + expect(ms(60 * 10000, { decimal: 1 })).to.be('10m'); + + expect(ms(-1 * 60 * 1000, { decimal: 1 })).to.be('-1m'); + expect(ms(-1 * 60 * 1200, { decimal: 1 })).to.be('-1.2m'); + expect(ms(-1 * 60 * 10000, { decimal: 1 })).to.be('-10m'); + }); + + it('should support hours', function() { + expect(ms(60 * 60 * 1000, { decimal: 1 })).to.be('1h'); + expect(ms(60 * 60 * 1200, { decimal: 1 })).to.be('1.2h'); + expect(ms(60 * 60 * 10000, { decimal: 1 })).to.be('10h'); + + expect(ms(-1 * 60 * 60 * 1000, { decimal: 1 })).to.be('-1h'); + expect(ms(-1 * 60 * 60 * 1200, { decimal: 1 })).to.be('-1.2h'); + expect(ms(-1 * 60 * 60 * 10000, { decimal: 1 })).to.be('-10h'); + }); + + it('should support days', function() { + expect(ms(24 * 60 * 60 * 1000, { decimal: 1 })).to.be('1d'); + expect(ms(24 * 60 * 60 * 1200, { decimal: 1 })).to.be('1.2d'); + expect(ms(24 * 60 * 60 * 10000, { decimal: 1 })).to.be('10d'); + + expect(ms(-1 * 24 * 60 * 60 * 1000, { decimal: 1 })).to.be('-1d'); + expect(ms(-1 * 24 * 60 * 60 * 1200, { decimal: 1 })).to.be('-1.2d'); + expect(ms(-1 * 24 * 60 * 60 * 10000, { decimal: 1 })).to.be('-10d'); + }); + + it('should round with 2 decimal place', function() { + expect(ms(234234234, { decimal: 2 })).to.be('2.71d'); + + expect(ms(-234234234, { decimal: 2 })).to.be('-2.71d'); + }); + + it('should round with up to 3 decimal place', function() { + expect(ms(234234234, { decimal: 3 })).to.be('2.711d'); + expect(ms(234234234, { decimal: 10 })).to.be('2.711d'); + + expect(ms(-234234234, { decimal: 3 })).to.be('-2.711d'); + expect(ms(-234234234, { decimal: 10 })).to.be('-2.711d'); + + expect(ms(ms('10.54321 hours'), { decimal: 1 })).to.be('10.5h'); + expect(ms(-3 * 66121, { decimal: 1 })).to.be('-3.3m'); + }); +}); + // invalid inputs describe('ms(invalid inputs)', function() {