Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
refactor: move unit stuff into Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
imurchie committed Dec 18, 2019
1 parent 7460540 commit f5a29b9
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 143 deletions.
103 changes: 39 additions & 64 deletions lib/timing.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,67 @@
import _ from 'lodash';


const DURATION_S = 's';
const DURATION_MS = 'ms';
const DURATION_NS = 'ns';

const NS_PER_SEC = 1e9;
const NS_PER_S = 1e9;
const NS_PER_MS = 1e6;

const CONVERSION_FACTORS = {
[DURATION_S]: NS_PER_SEC,
[DURATION_MS]: NS_PER_MS,
[DURATION_NS]: 1,
};


/**
* Class representing a duration, encapsulating the number and units.
*/
class Duration {
constructor (duration, units) {
constructor (duration) {
this._duration = duration;
this._units = units;
}

get duration () {
return this._duration;
}

get units () {
return this._units;
/**
* Get the duration as nanoseconds
*
* @returns {number} The duration as nanoseconds
*/
get asNanoSeconds () {
return this.duration;
}

/**
* Get the duration converted into milliseconds
*
* @returns {number} The duration as milliseconds
*/
get asMilliSeconds () {
return this.duration / NS_PER_MS;
}

/**
* Get the duration converted into seconds
*
* @returns {number} The duration fas seconds
*/
get asSeconds () {
return this.duration / NS_PER_S;
}

toString () {
return `${this.duration}${this.units}`;
// default to milliseconds, rounded
return this.asMilliSeconds.toFixed(0);
}
}

class Timer {
/**
* Creates a timer
*
* @param {?string} units - the default units for conversion
*/
constructor (units = DURATION_MS) {
if (!_.keys(CONVERSION_FACTORS).includes(units)) {
throw new Error(`Unknown unit for duration conversion: '${units}'. Available units: ${_.keys(CONVERSION_FACTORS).join(', ')}`);
}

this._units = units;
constructor () {
this._startTime = null;
}

get startTime () {
return this._startTime;
}

get units () {
return this._units;
}

/**
* Start the timer
*
Expand All @@ -76,48 +78,21 @@ class Timer {
return this;
}

/**
* @typedef {Object} GetDurationOptions
*
* @property {?string} units - the units to convert to. Can be one of
* - 's' - seconds (default)
* - 'ms' - milliseconds
* - 'ns' - nanoseconds
* @property {?boolean} round - whether or not the result should be rounded to
* the nearest integer
*/

/**
* Get the duration since the timer was started
*
* @param {?string|GetDurationOptions} opts - options for conversion of duration.
* Can be a String representing the units ('s', 'ms', or 'ns') or an Object
* @return {Duration} the duration, in the specified units
*/
getDuration (opts = {}) {
getDuration () {
if (_.isNull(this.startTime)) {
throw new Error(`Unable to get duration. Timer was not started`);
}

if (_.isString(opts)) {
opts = {
units: opts,
};
}
const {
units = this.units,
round = true,
} = opts;

if (!_.keys(CONVERSION_FACTORS).includes(units)) {
throw new Error(`Unknown unit for duration conversion: '${units}'. Available units: ${_.keys(CONVERSION_FACTORS).join(', ')}`);
}

let nanoDuration;
if (_.isArray(this.startTime)) {
// startTime was created using process.hrtime()
const [seconds, nanos] = process.hrtime(this.startTime);
nanoDuration = seconds * NS_PER_SEC + nanos;
nanoDuration = seconds * NS_PER_S + nanos;
} else if (typeof this.startTime === 'bigint' && _.isFunction(process.hrtime.bigint)) {
// startTime was created using process.hrtime.bigint()
const endTime = process.hrtime.bigint();
Expand All @@ -127,18 +102,18 @@ class Timer {
throw new Error(`Unable to get duration. Start time '${this.startTime}' cannot be parsed`);
}

const duration = nanoDuration / CONVERSION_FACTORS[units];
return new Duration(round ? Math.round(duration) : duration, units);
return new Duration(nanoDuration);
}

toString () {
return this.getDuration().toString();
try {
return this.getDuration().toString();
} catch (err) {
return `<err: ${err.message}>`;
}
}
}


export {
Timer, Duration,
DURATION_S, DURATION_MS, DURATION_NS,
};
export { Timer, Duration };
export default Timer;
99 changes: 20 additions & 79 deletions test/timing-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,58 +37,33 @@ describe('timing', function () {
const timer = new timing.Timer().start();
const duration = timer.getDuration();
_.isNumber(duration.duration).should.be.true;
_.isString(duration.units).should.be.true;
});
it('should get correct s', function () {
it('should get correct seconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_S,
round: false,
});
duration.duration.should.eql(13.000054321);
duration.units.should.eql('s');
});
it('should get correct s rounded', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_S,
});
duration.duration.should.eql(13);
duration.units.should.eql('s');
const duration = timer.getDuration();
duration.asSeconds.should.eql(13.000054321);
});
it('should get correct ms', function () {
it('should get correct milliseconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_MS,
round: false,
});
duration.duration.should.eql(13000.054321);
duration.units.should.eql('ms');
});
it('should get correct ns', function () {
const duration = timer.getDuration();
duration.asMilliSeconds.should.eql(13000.054321);
});
it('should get correct nanoseconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_NS,
round: false,
});
duration.duration.should.eql(13000054321);
duration.units.should.eql('ns');
const duration = timer.getDuration();
duration.asNanoSeconds.should.eql(13000054321);
});
it('should error if the timer was not started', function () {
const timer = new timing.Timer();
Expand All @@ -101,11 +76,6 @@ describe('timing', function () {
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
it('should error if passing in wrong unit', function () {
const timer = new timing.Timer().start();
expect(() => timer.getDuration('ds'))
.to.throw('Unknown unit for duration');
});
});
describe('bigint', function () {
beforeEach(function () {
Expand Down Expand Up @@ -137,48 +107,26 @@ describe('timing', function () {
const duration = timer.getDuration();
_.isNumber(duration.duration).should.be.true;
});
it('should get correct s', function () {
it('should get correct seconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_S,
round: false,
});
duration.duration.should.be.eql(10.011483102);
duration.units.should.eql('s');
});
it('should get correct s rounded', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_S,
});
duration.duration.should.be.eql(10);
duration.units.should.eql('s');
const duration = timer.getDuration();
duration.asSeconds.should.be.eql(10.011483102);
});
it('should get correct ms', function () {
it('should get correct milliseconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_MS,
round: false,
});
duration.duration.should.be.eql(10011.483102);
duration.units.should.eql('ms');
});
it('should get correct ns', function () {
const duration = timer.getDuration();
duration.asMilliSeconds.should.be.eql(10011.483102);
});
it('should get correct nanoseconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration({
units: timing.DURATION_NS,
round: false,
});
duration.duration.should.be.eql(10011483102);
duration.units.should.eql('ns');
const duration = timer.getDuration();
duration.asNanoSeconds.should.be.eql(10011483102);
});
it('should error if the timer was not started', function () {
const timer = new timing.Timer();
Expand All @@ -191,12 +139,5 @@ describe('timing', function () {
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
it('should error if passing in wrong unit', function () {
setupMocks(true);

const timer = new timing.Timer().start();
expect(() => timer.getDuration('ds'))
.to.throw('Unknown unit for duration');
});
});
});

0 comments on commit f5a29b9

Please sign in to comment.