How can I convert performance.now() output to a UTC String?

7.4k views Asked by At

In our code, we were previously calculating the difference between to events like so:

var beginTime = new Date();
// Do stuff
var endTime = new Date();
var duration = endTime.getTime() - beginTime.getTime();

console.log("Job began at " + beginTime.toUTCString()
            + " and took " + duration + " milliseconds.");

This results in a human-readable string:

Job began at Thu Sep 28 2017 11:17:33 GMT-0500 (Central Daylight Time) and took 7000 milliseconds.

We've decided to switch to High Resolution Time by using the more reliable performance.now(). However, we still want to be able have a human-readable UTC time string included.

Initially, we tried this:

var beginTime = performance.now();
// Do stuff
var endTime = performance.now();
var duration = endTime - beginTime;

console.log("Job began at " + new Date(beginTime).toUTCString() 
            + " and took " + duration + " seconds.");

We are finding that the duration is accurate, but new Date(performance.now()) results in an inaccurate UTC value (at the time of this writing, it provides a date nearly 50 years in the past).

Job began at Wed Dec 31 1969 20:10:46 GMT-0600 (Central Standard Time) and took 7000 milliseconds.

Is there a better way to convert the output of performance.now() to an accurate UTC string? It doesn't have to be the exact same format as new Date().toUTCString(), but it should be human-readable.

4

There are 4 answers

0
Przemek On BEST ANSWER

It can be done like this:

const t0 = performance.now();

// measured job here

const t1     = performance.now(),
      t0Date = new Date(performance.timing.navigationStart + t0).toUTCString();

console.log(`Job began at ${t0Date} and took ${t1 - t0} milliseconds.`);
/* Console formatting only */
.as-console-wrapper { top: 0; }

Note however that after performance.now() MDN page (emphasis mine):

(…) performance.timing.navigationStart + performance.now() will be approximately equal to Date.now().

For me, it's within one second of actual time start.

2
Bergi On

This is not possible. The return values of performance.now do have the page load as their origin (0) value, and cannot be transformed into a date. According to the spec, you should be able to sum it with performance.timeOrigin to obtain a unix timestamp, however there doesn't seem to be any browser support for this.

If you want to know when your measuring started in wall clock time, I recommend to store a conventional new Date/Date.now() timestamp as well.

0
Thusitha On

From the MDN,

unlike Date.now(), the values returned by Performance.now() always increase at a constant rate, independent of the system clock (which might be adjusted manually or skewed by software like NTP). Otherwise, performance.timing.navigationStart + performance.now() will be approximately equal to Date.now()

As the name implies performance.now() is to measure performance up to an accuracy of 5 microseconds between two tasks and not to keep the UNIX timeStamp.

performance.timing.navigationStart + performance.now() will be approximately equal to Date.now()

Read more about here.
https://developer.mozilla.org/en-US/docs/Web/API/Performance/now

0
AudioBubble On

I would do it like this:

// mark the start time
performance.mark("start");

// ... 
//  later...
// ...
// mark the end time
performance.mark("end");

// create a measure called 'm' based on the two marks above
performance.measure("m", "start", "end");

// get the start mark, calculate its real-world timestamp using the time origin
var started = performance.getEntriesByName("start")[0];
var startedDt = new Date(performance.timing.navigationStart + started.startTime);

// get the measure we created above
var duration = performance.getEntriesByName("m")[0];
console.log(`job began on ${startedDt} and took ${duration.duration/1000.0} seconds`);

performance.clearMarks();

First, mark the start and end times for your duration measurement. Second, create a duration measurement.

Later on, you get your start and end marks, calculate the started date by combining the time origin with the start mark's timestamp. Lastly, clear the marks.

It's not strictly necessary to get the start mark... you can also calculate the real-world start timestamp from the measure m, which also has a startTime. I used the start mark, but either is valid.

In other words, you can also do this:

// get the measure we created above
var duration = performance.getEntriesByName("m")[0];
var startedDt = new Date(performance.timing.navigationStart + duration.startTime);

console.log(`job began on ${startedDt} and took ${duration.duration/1000.0} seconds`);