33

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.

6
  • W3Schools show something similar. Commented Feb 24, 2012 at 15:49
  • What do you mean by session? Where do you run this code (browser, server)? Commented Feb 25, 2012 at 10:39
  • Sorry, I had worded that poorly. Hopefully the change I just added is clearer. Commented Feb 26, 2012 at 1:17
  • 1
    @xyu: w3schools is not really a good site - w3fools.com - the fact that they pass a string to setTimeout clearly proves that. Commented Feb 26, 2012 at 14:08
  • @ThiefMaster Yes I know. But I meant the idea of increasing a variable using setTimeout. Commented Feb 26, 2012 at 14:12

3 Answers 3

29

You could use window.performance.now() - since Firefox 15, and window.performance.webkitNow() - Chrome 20]

var a = window.performance.now();
//...
var delay = window.performance.now() - a;
Sign up to request clarification or add additional context in comments.

4 Comments

This function is also available in IE10.
Web worker uses different time origin. developer.mozilla.org/en-US/docs/Web/API/…
Bit of warning, this doesn't actually appear to be monotonic in the sense that I was hoping for (the POSIX monotonic clock). Specifically, it does not account for time spent in sleep mode.
It should account for time spent in sleep mode, but there are bugs in browsers. See this note.
7
+150

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.

3 Comments

Yes, good point and answered as I originally asked. I have modified my original question to add the accuracy requirement.
A kind-of obvious comment that isn't an issue for the original question in the way it is asked, but it might be important for some none-the-less: This solution does not handle the case where the user sets the clock forward, i.e. it does not prevent large positive jumps in the returned time.
@MarkusA. It seemed worth discussing, so I added a section on that.
4

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…

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.