Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monotonically increasing time in JavaScript?

What’s the best way to get monotonically increasing time in JavaScript? I’m hoping for something like Java’s System.nanoTime().

Date() obviously won’t work, as it’s affected by system time changes.

In other words, what I would like is for a <= b, always:

a = myIncreasingTime.getMilliseconds();
...
// some time later, maybe seconds, maybe days
b = myIncreasingTime.getMilliseconds();

At best, even when using the UTC functions in Date(), it will return what it believes is the correct time, but if someone sets the time backward, the next call to Date() can return a lesser value. System.nanoTime() does not suffer from this limitation (at least not until the system is rebooted).

Modification: [2012-02-26: not intended to affect the original question, which has a bounty]

I am not interested knowing the “wall time”, I’m interested in knowing elapsed time with some accuracy, which Date() cannot possibly provide.

like image 281
danorton Avatar asked Sep 01 '11 15:09

danorton


3 Answers

Firefox provides "delay" argument for setTimeout... this is the one of ways to implement monotonically increased time counter.

var time = 0;

setTimeout(function x(actualLateness) {
  setTimeout(x, 0);
  time += actualLateness;
}, 0);
like image 89
4esn0k Avatar answered Oct 22 '22 00:10

4esn0k


You could wrap Date() or Date.now() so as to force it to be monotonic (but inaccurate). Sketch, untested:

var offset = 0;
var seen = 0;
function time() {
  var t = Date.now();
  if (t < seen) {
    offset += (seen - t);
  }
  seen = t;
  return t + offset;
}

If the system clock is set back at a given moment, then it will appear that no time has passed (and an elapsed time containing that interval will be incorrect), but you will at least not have negative deltas. If there are no set-backs then this returns the same value as Date.now().

This might be a suitable solution if you're writing a game simulation loop, for example, where time() is called extremely frequently — the maximum error is the number of set-backs times the interval between calls. If your application doesn't naturally do that, you could explicitly call it on a setInterval, say (assuming that isn't hosed by the system clock), to keep your accuracy at the cost of some CPU time.


It is also possible that the clock will be set forward, which does not prevent monotonicity but might have equally undesirable effects (e.g. a game spending too long trying to catch up its simulation at once). However, this is not especially distinguishable from the machine having been asleep for some time. If such a protection is desired, it just means changing the condition next to the existing one, with a constant threshold for acceptable progress:

if (t > seen + leapForwardMaximum) {
  offset += (seen - t) + leapForwardMaximum;
}

I would suggest that leapForwardMaximum should be set to more than 1000 ms because, for example, Chrome (if I recall correctly) throttles timers in background tabs to fire not more than once per second.

like image 45
Kevin Reid Avatar answered Oct 21 '22 23:10

Kevin Reid


Javascript itself does not have any functionality to access the nanoTime. You might load a java-applet to aqcuire that information, like benchmark.js has done. Maybe @mathias can shed some light on what they did there…

like image 4
rodneyrehm Avatar answered Oct 21 '22 22:10

rodneyrehm