Skip to content

Commit

Permalink
refactor(core): avoid unnecessary stringify in numberToHrtime
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas committed Dec 9, 2022
1 parent fb87ee9 commit 2759fc3
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 13 deletions.
16 changes: 4 additions & 12 deletions packages/opentelemetry-core/src/common/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,20 @@ import { otperformance as performance } from '../platform';
import { TimeOriginLegacy } from './types';

const NANOSECOND_DIGITS = 9;
const NANOSECOND_DIGITS_IN_MILLIS = 6;
const MILLISECONDS_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS_IN_MILLIS);
const SECOND_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS);

/**
* Converts a number to HrTime, HrTime = [number, number].
* The first number is UNIX Epoch time in seconds since 00:00:00 UTC on 1 January 1970.
* The second number represents the partial second elapsed since Unix Epoch time represented by first number in nanoseconds.
* For example, 2021-01-01T12:30:10.150Z in UNIX Epoch time in milliseconds is represented as 1609504210150.
* numberToHrtime calculates the first number by converting and truncating the Epoch time in milliseconds to seconds:
* HrTime[0] = Math.trunc(1609504210150 / 1000) = 1609504210.
* numberToHrtime calculates the second number by converting the digits after the decimal point of the subtraction, (1609504210150 / 1000) - HrTime[0], to nanoseconds:
* HrTime[1] = Number((1609504210.150 - HrTime[0]).toFixed(9)) * SECOND_TO_NANOSECONDS = 150000000.
* This is represented in HrTime format as [1609504210, 150000000].
* Converts a number of milliseconds from epoch to HrTime([seconds, remainder in nanoseconds]).
* @param epochMillis
*/
function numberToHrtime(epochMillis: number): api.HrTime {
const epochSeconds = epochMillis / 1000;
// Decimals only.
const seconds = Math.trunc(epochSeconds);
// Round sub-nanosecond accuracy to nanosecond.
const nanos =
Number((epochSeconds - seconds).toFixed(NANOSECOND_DIGITS)) *
SECOND_TO_NANOSECONDS;
const nanos = (epochMillis % 1000) * MILLISECONDS_TO_NANOSECONDS;
return [seconds, nanos];
}

Expand Down
18 changes: 17 additions & 1 deletion packages/opentelemetry-core/test/common/time.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('time', () => {
it('should convert Date hrTime', () => {
const timeInput = new Date(1609297640313);
const output = timeInputToHrTime(timeInput);
assert.deepStrictEqual(output, [1609297640, 312999964]);
assert.deepStrictEqual(output, [1609297640, 313000000]);
});

it('should convert epoch milliseconds hrTime', () => {
Expand All @@ -114,6 +114,22 @@ describe('time', () => {
assert.deepStrictEqual(output[0], Math.trunc(timeInput / 1000));
});

it('should convert arbitrary epoch milliseconds hrTime', () => {
sinon.stub(performance, 'timeOrigin').value(111.5);
const inputs = [
// [ input, expected ]
[1609297640313, [1609297640, 313000000]],
// inevitable precision loss without decimal arithmetics.
[1609297640313.333, [1609297640, 313333007.8125]],
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
[1609297640313.333333, [1609297640, 313333251.953125]],
] as const;
for (const [idx, input] of inputs.entries()) {
const output = timeInputToHrTime(input[0]);
assert.deepStrictEqual(output, input[1], `input[${idx}]: ${input}`);
}
});

it('should convert performance.now() hrTime', () => {
sinon.stub(performance, 'timeOrigin').value(111.5);

Expand Down

0 comments on commit 2759fc3

Please sign in to comment.