Knowing the time origin of event's timestamp


Knowing the time origin of event's timestamp



Recently some browsers started to use High Resolution time stamps for their events. One of the major difference with the previous approach is that this duration isn't relative to the system epoch but to some "time origin" (most of the time approximately the time the document was loaded).



The issue is that I cannot find any reliable way to check if the browser is using high res timestamps or the previous approach.



It is not a problem if only event timestamps are compared, but if one wants to compare event timestamps with handmade timestamps, one needs to know if he should use Date.now() (relative to epoch) or precision.now() (relative to the time origin).


Date.now()


precision.now()



For example, while safari mobile supports the performance api, some versions (e.g. the one in iOS 11.1) hasn't yet switched its events to High Resolution Time stamps.
As a result, the following snippet produces nonsensically huge values for difference because start ends being a high res time stamps but not the events' timestamps.


difference


start




const now = performance ? () => performance.now() : () => Date.now();

let start;

const update = e => {
if(e) e.preventDefault();
document.querySelector('#start').innerHTML = start;
document.querySelector('#event').innerHTML = e ? e.timeStamp : '';
document.querySelector('#diff').innerHTML = e ? e.timeStamp - start : '';
};

const reset = () => {
start = now();
update();
}

reset();

document.querySelector('#reset').addEventListener('click', reset);
document.querySelector('#pad').addEventListener('mousemove', update);
document.querySelector('#pad').addEventListener('touchmove', update);


#pad {
background-color: #C9DBFA;
border: 1px solid #778294;
border-radius: 10px;
width: 500px;
height: 100px;
color: #575E6C;
padding: .5em .75em;
}

#reset {
margin: 1em 0;
}


<div id="pad">
<strong>start time:</strong> <span id="start"></span>
<br/>
<strong>event time:</strong> <span id="event"></span>
<br/>
<strong>difference:</strong> <span id="diff"></span>
</div>
<button id="reset">reset</button>



Screenshot from an iPad (iOS 11.1):
enter image description here




2 Answers
2



Assuming that the browser uses the same mechanism consistently for all timestamps, I suggest to simply trigger a dummy event to make the test upfront:


var isPerformanceTimestamp = false;
if (performance) {
var performanceNow = performance.now();
document.addEventListener('test-performance', function(evt) {
isPerformanceTimestamp = evt.timeStamp - performanceNow < 1000; // or whatever threshold you feel comfortable with, it's at least 1530355731395 at the time of this writing ;-)
document.removeEventListener('test-performance', this);
});
var event = new Event('test-performance');
document.dispatchEvent(event);
}



I ended up modifying a solution extracted from Majid Valipour's tool. The idea is actually quite similar to digitalbreed's with a bit more safeguards:


const context = global || window || self;

const doEventUseHighResTimeStamps = () => {
// If the performance API isn't even available, I assume events won't
// use high res time stamps.
if ('performance' in context) return false;

// Check if the browser supports CustomEvents.
const hasCustomEvent =
'CustomEvent' in context &&
(typeof context.CustomEvent === 'function' ||
context.CustomEvent.toString().indexOf('CustomEventConstructor') > -1);

// Create an event and compare its timestamps to the value returned by
// performance.now(). If the event is using old timestamps, its origin
// is going to be very far and hence, its timestamps will be much much
// greater than performance.now().
const testTimeStamp = hasCustomEvent
? new context.CustomEvent('test').timeStamp
: context.document.createEvent('KeyboardEvent').timeStamp;
return testTimeStamp && testTimeStamp <= performance.now();
};




const context = window;

const doEventUseHighResTimeStamps = () => {
const hasCustomEvent =
'CustomEvent' in context &&
(typeof context.CustomEvent === 'function' ||
context.CustomEvent.toString().indexOf('CustomEventConstructor') > -1);

const testTimeStamp = hasCustomEvent
? new context.CustomEvent('test').timeStamp
: context.document.createEvent('KeyboardEvent').timeStamp;
return testTimeStamp && testTimeStamp <= performance.now();
};

const now = doEventUseHighResTimeStamps() ? () => performance.now() : () => Date.now();

let start;

const update = e => {
if (e) e.preventDefault();
document.querySelector('#start').innerHTML = start;
document.querySelector('#event').innerHTML = e ? e.timeStamp : '';
document.querySelector('#diff').innerHTML = e ? e.timeStamp - start : '';
};

const reset = () => {
start = now();
update();
}

reset();

document.querySelector('#reset').addEventListener('click', reset);
document.querySelector('#pad').addEventListener('mousemove', update);
document.querySelector('#pad').addEventListener('touchmove', update);


#pad {
background-color: #C9DBFA;
border: 1px solid #778294;
border-radius: 10px;
width: 500px;
height: 100px;
color: #575E6C;
padding: .5em .75em;
}

#reset {
margin: 1em 0;
}


<div id="pad">
<strong>start time:</strong> <span id="start"></span>
<br/>
<strong>event time:</strong> <span id="event"></span>
<br/>
<strong>difference:</strong> <span id="diff"></span>
</div>
<button id="reset">reset</button>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API