├── .gitignore ├── .jshintignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── minimal.js ├── precise.js ├── smoke.js └── verbose.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | components 7 | *.orig 8 | .idea 9 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | components 7 | *.orig 8 | .idea 9 | test 10 | .travis.yml 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - "4" 6 | - "5" 7 | - "6" 8 | - "7" 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 [Richardson & Sons, LLC](http://richardsonandsons.com/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://secure.travis-ci.org/robrich/pretty-hrtime.png?branch=master)](https://travis-ci.org/robrich/pretty-hrtime) 2 | [![Dependency Status](https://david-dm.org/robrich/pretty-hrtime.png)](https://david-dm.org/robrich/pretty-hrtime) 3 | 4 | pretty-hrtime 5 | ============ 6 | 7 | [process.hrtime()](http://nodejs.org/api/process.html#process_process_hrtime) to words 8 | 9 | Usage 10 | ----- 11 | 12 | ```javascript 13 | var prettyHrtime = require('pretty-hrtime'); 14 | 15 | var start = process.hrtime(); 16 | // do stuff 17 | var end = process.hrtime(start); 18 | 19 | var words = prettyHrtime(end); 20 | console.log(words); // '1.2 ms' 21 | 22 | words = prettyHrtime(end, {verbose:true}); 23 | console.log(words); // '1 millisecond 209 microseconds' 24 | 25 | words = prettyHrtime(end, {precise:true}); 26 | console.log(words); // '1.20958 ms' 27 | ``` 28 | 29 | Note: process.hrtime() has been available since 0.7.6. 30 | See [http://nodejs.org/changelog.html](http://nodejs.org/changelog.html) 31 | and [https://github.com/joyent/node/commit/f06abd](https://github.com/joyent/node/commit/f06abd). 32 | 33 | LICENSE 34 | ------- 35 | 36 | (MIT License) 37 | 38 | Copyright (c) 2013 [Richardson & Sons, LLC](http://richardsonandsons.com/) 39 | 40 | Permission is hereby granted, free of charge, to any person obtaining 41 | a copy of this software and associated documentation files (the 42 | "Software"), to deal in the Software without restriction, including 43 | without limitation the rights to use, copy, modify, merge, publish, 44 | distribute, sublicense, and/or sell copies of the Software, and to 45 | permit persons to whom the Software is furnished to do so, subject to 46 | the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be 49 | included in all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 52 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 53 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 54 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 55 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 56 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 57 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 3 | "use strict"; 4 | 5 | var minimalDesc = ['h', 'min', 's', 'ms', 'μs', 'ns']; 6 | var verboseDesc = ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond']; 7 | var convert = [60*60, 60, 1, 1e6, 1e3, 1]; 8 | 9 | module.exports = function (source, opts) { 10 | var verbose, precise, i, spot, sourceAtStep, valAtStep, decimals, strAtStep, results, totalSeconds; 11 | 12 | verbose = false; 13 | precise = false; 14 | if (opts) { 15 | verbose = opts.verbose || false; 16 | precise = opts.precise || false; 17 | } 18 | 19 | if (!Array.isArray(source) || source.length !== 2) { 20 | return ''; 21 | } 22 | if (typeof source[0] !== 'number' || typeof source[1] !== 'number') { 23 | return ''; 24 | } 25 | 26 | // normalize source array due to changes in node v5.4+ 27 | if (source[1] < 0) { 28 | totalSeconds = source[0] + source[1] / 1e9; 29 | source[0] = parseInt(totalSeconds); 30 | source[1] = parseFloat((totalSeconds % 1).toPrecision(9)) * 1e9; 31 | } 32 | 33 | results = ''; 34 | 35 | // foreach unit 36 | for (i = 0; i < 6; i++) { 37 | spot = i < 3 ? 0 : 1; // grabbing first or second spot in source array 38 | sourceAtStep = source[spot]; 39 | if (i !== 3 && i !== 0) { 40 | sourceAtStep = sourceAtStep % convert[i-1]; // trim off previous portions 41 | } 42 | if (i === 2) { 43 | sourceAtStep += source[1]/1e9; // get partial seconds from other portion of the array 44 | } 45 | valAtStep = sourceAtStep / convert[i]; // val at this unit 46 | if (valAtStep >= 1) { 47 | if (verbose) { 48 | valAtStep = Math.floor(valAtStep); // deal in whole units, subsequent laps will get the decimal portion 49 | } 50 | if (!precise) { 51 | // don't fling too many decimals 52 | decimals = valAtStep >= 10 ? 0 : 2; 53 | strAtStep = valAtStep.toFixed(decimals); 54 | } else { 55 | strAtStep = valAtStep.toString(); 56 | } 57 | if (strAtStep.indexOf('.') > -1 && strAtStep[strAtStep.length-1] === '0') { 58 | strAtStep = strAtStep.replace(/\.?0+$/,''); // remove trailing zeros 59 | } 60 | if (results) { 61 | results += ' '; // append space if we have a previous value 62 | } 63 | results += strAtStep; // append the value 64 | // append units 65 | if (verbose) { 66 | results += ' '+verboseDesc[i]; 67 | if (strAtStep !== '1') { 68 | results += 's'; 69 | } 70 | } else { 71 | results += ' '+minimalDesc[i]; 72 | } 73 | if (!verbose) { 74 | break; // verbose gets as many groups as necessary, the rest get only one 75 | } 76 | } 77 | } 78 | 79 | return results; 80 | }; 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pretty-hrtime", 3 | "description": "process.hrtime() to words", 4 | "version": "1.0.3", 5 | "homepage": "https://github.com/robrich/pretty-hrtime", 6 | "repository": "git://github.com/robrich/pretty-hrtime.git", 7 | "author": "Rob Richardson (http://robrich.org/)", 8 | "main": "./index.js", 9 | "keywords": [ 10 | "hrtime", 11 | "benchmark" 12 | ], 13 | "devDependencies": { 14 | "jshint": "^2.9.4", 15 | "mocha": "^3.1.2", 16 | "should": "^11.2.1" 17 | }, 18 | "scripts": { 19 | "test": "mocha && jshint ." 20 | }, 21 | "engines": { 22 | "node": ">= 0.8" 23 | }, 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /test/minimal.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | /*global describe:false, it:false */ 3 | 4 | "use strict"; 5 | 6 | var prettyHrtime = require('../'); 7 | require('should'); 8 | require('mocha'); 9 | 10 | describe('pretty-hrtime', function() { 11 | describe('minimal', function () { 12 | 13 | var runTest = function (expected, source) { 14 | var actual; 15 | 16 | // Arrange 17 | 18 | // Act 19 | actual = prettyHrtime(source); 20 | 21 | // Assert 22 | actual.should.equal(expected); 23 | }; 24 | 25 | it('1.2m', function() { 26 | runTest('1.2 min', [72, 100]); 27 | }); 28 | 29 | it('48s', function() { 30 | runTest('48 s', [48, 100]); 31 | }); 32 | 33 | it('1.02s', function() { 34 | runTest('1.02 s', [1, 2.02e7]); 35 | }); 36 | 37 | it('840ms', function() { 38 | runTest('840 ms', [0, 8.4005e8]); 39 | }); 40 | 41 | it('600ms', function() { 42 | runTest('600 ms', [0, 6.004e8]); 43 | }); 44 | 45 | it('200ms', function() { 46 | runTest('200 ms', [0, 2.004e8]); 47 | }); 48 | 49 | it('1.2ms', function() { 50 | runTest('1.2 ms', [0, 1.2004e6]); 51 | }); 52 | 53 | it('600μs', function() { 54 | runTest('600 μs', [0, 600200]); 55 | }); 56 | 57 | it('1.2μs', function() { 58 | runTest('1.2 μs', [0, 1204]); 59 | }); 60 | 61 | it('600ns', function() { 62 | runTest('600 ns', [0, 600]); 63 | }); 64 | 65 | // Node v5.4+ negative nano values 66 | it('31s', function() { 67 | runTest('31 s', [31, -97909258]); 68 | }); 69 | 70 | it('2.9s', function() { 71 | runTest('2.9 s', [3, -95038258]); 72 | }); 73 | 74 | it('603ms', function() { 75 | runTest('603 ms', [1, -396570776]); 76 | }); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /test/precise.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | /*global describe:false, it:false */ 3 | 4 | "use strict"; 5 | 6 | var prettyHrtime = require('../'); 7 | require('should'); 8 | require('mocha'); 9 | 10 | describe('pretty-hrtime', function() { 11 | describe('precise', function () { 12 | 13 | var runTest = function (expected, source) { 14 | var actual; 15 | 16 | // Arrange 17 | 18 | // Act 19 | actual = prettyHrtime(source, {precise:true}); 20 | 21 | // Assert 22 | actual.should.equal(expected); 23 | }; 24 | 25 | it('1.2m', function() { 26 | runTest('1.2 min', [72, 100]); 27 | }); 28 | 29 | it('48s', function() { 30 | runTest('48.0000001 s', [48, 100]); 31 | }); 32 | 33 | it('1.02s', function() { 34 | runTest('1.0202 s', [1, 2.02e7]); 35 | }); 36 | 37 | it('840ms', function() { 38 | runTest('840.05 ms', [0, 8.4005e8]); 39 | }); 40 | 41 | it('600ms', function() { 42 | runTest('600.5 ms', [0, 6.005e8]); 43 | }); 44 | 45 | it('200ms', function() { 46 | runTest('200.5 ms', [0, 2.005e8]); 47 | }); 48 | 49 | it('1.2ms', function() { 50 | runTest('1.2005 ms', [0, 1.2005e6]); 51 | }); 52 | 53 | it('600μs', function() { 54 | runTest('600.2 μs', [0, 600200]); 55 | }); 56 | 57 | it('1.2μs', function() { 58 | runTest('1.204 μs', [0, 1204]); 59 | }); 60 | 61 | it('600ns', function() { 62 | runTest('600 ns', [0, 600]); 63 | }); 64 | 65 | // Node v5.4+ negative nano values 66 | it('31s', function() { 67 | runTest('30.902090742 s', [31, -97909258]); 68 | }); 69 | 70 | it('2.9s', function() { 71 | runTest('2.9049617420000002 s', [3, -95038258]); 72 | }); 73 | 74 | it('603ms', function() { 75 | runTest('603.429224 ms', [1, -396570776]); 76 | }); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /test/smoke.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | /*global describe:false, it:false */ 3 | 4 | "use strict"; 5 | 6 | var prettyHrtime = require('../'); 7 | require('should'); 8 | require('mocha'); 9 | 10 | describe('pretty-hrtime', function() { 11 | describe('smoke', function () { 12 | 13 | it('should work', function(done) { 14 | var duration, regex, startTime, doneTime, actual, match; 15 | 16 | // Arrange 17 | duration = 100; 18 | regex = /^1\d\d ms/; 19 | 20 | // Act 21 | startTime = process.hrtime(); 22 | 23 | setTimeout(function () { 24 | doneTime = process.hrtime(startTime); 25 | 26 | actual = prettyHrtime(doneTime); 27 | 28 | // Assert 29 | match = regex.test(actual); 30 | match.should.equal(true); 31 | 32 | done(); 33 | }, duration); 34 | }); 35 | 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/verbose.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | /*global describe:false, it:false */ 3 | 4 | "use strict"; 5 | 6 | var prettyHrtime = require('../'); 7 | require('should'); 8 | require('mocha'); 9 | 10 | describe('pretty-hrtime', function() { 11 | describe('verbose', function () { 12 | 13 | var runTest = function (expected, source) { 14 | var actual; 15 | 16 | // Arrange 17 | 18 | // Act 19 | actual = prettyHrtime(source, {verbose:true}); 20 | 21 | // Assert 22 | actual.should.equal(expected); 23 | }; 24 | 25 | it('1.2h', function() { 26 | runTest('1 hour 12 minutes 10 seconds', [4330, 0]); 27 | }); 28 | 29 | it('1.2m', function() { 30 | runTest('1 minute 12 seconds 100 nanoseconds', [72, 100]); 31 | }); 32 | 33 | it('1m', function() { 34 | runTest('1 minute 100 nanoseconds', [60, 100]); 35 | }); 36 | 37 | it('48s', function() { 38 | runTest('48 seconds 100 nanoseconds', [48, 100]); 39 | }); 40 | 41 | it('1.02s', function() { 42 | runTest('1 second 20 milliseconds 200 microseconds', [1, 2.02e7]); 43 | }); 44 | 45 | it('840ms', function() { 46 | runTest('840 milliseconds 50 microseconds', [0, 8.4005e8]); 47 | }); 48 | 49 | it('600ms', function() { 50 | runTest('600 milliseconds 500 microseconds', [0, 6.005e8]); 51 | }); 52 | 53 | it('200ms', function() { 54 | runTest('200 milliseconds 500 microseconds', [0, 2.005e8]); 55 | }); 56 | 57 | it('1.2ms', function() { 58 | runTest('1 millisecond 200 microseconds 500 nanoseconds', [0, 1.2005e6]); 59 | }); 60 | 61 | it('600μs', function() { 62 | runTest('600 microseconds 200 nanoseconds', [0, 600200]); 63 | }); 64 | 65 | it('1.2μs', function() { 66 | runTest('1 microsecond 204 nanoseconds', [0, 1204]); 67 | }); 68 | 69 | it('600ns', function() { 70 | runTest('600 nanoseconds', [0, 600]); 71 | }); 72 | 73 | // Node v5.4+ negative nano values 74 | it('31s', function() { 75 | runTest('30 seconds 902 milliseconds 90 microseconds 742 nanoseconds', [31, -97909258]); 76 | }); 77 | 78 | it('2.9s', function() { 79 | runTest('2 seconds 904 milliseconds 961 microseconds 742 nanoseconds', [3, -95038258]); 80 | }); 81 | 82 | it('603ms', function() { 83 | runTest('603 milliseconds 429 microseconds 224 nanoseconds', [1, -396570776]); 84 | }); 85 | }); 86 | }); 87 | --------------------------------------------------------------------------------