Synchronize time in javascript with a good precision (>0.5s) (NTP-like)

micred picture micred · Dec 12, 2011 · Viewed 12.3k times · Source

I'm looking for a way to synchronize time between clients with a good precision (let's say 0.5 seconds at least).

I exclude using jsontime or exploiting timestamp in server response headers due to a poor precision (a second or maybe less).

UPDATE: It should work even with mobile connections. It's not unfrequent (e.g. here in Italy) that 3G connections itself have a round trip time around 0.5s, so algorithm has to be robust.

Answer

Aadit M Shah picture Aadit M Shah · Dec 12, 2011

Resort to the good old ICMP Timestamp message scheme. It's fairly trivial to implement in JavaScript and PHP.

Here's an implementation of this scheme using JavaScript and PHP:

// browser.js

var request = new XMLHttpRequest();
request.onreadystatechange = readystatechangehandler;
request.open("POST", "http://www.example.com/sync.php", true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("original=" + (new Date).getTime());

function readystatechangehandler() {
    var returned = (new Date).getTime();
    if (request.readyState === 4 && request.status === 200) {
        var timestamp = request.responseText.split('|');
        var original = + timestamp[0];
        var receive = + timestamp[1];
        var transmit = + timestamp[2];
        var sending = receive - original;
        var receiving = returned - transmit;
        var roundtrip = sending + receiving;
        var oneway = roundtrip / 2;
        var difference = sending - oneway; // this is what you want
        // so the server time will be client time + difference
    }
}

Now for the sync.php code:

<?php
    $receive = round(microtime(true) * 1000);
    echo $_POST["original"] . '|';
    echo $receive . '|';
    echo round(microtime(true) * 1000);
?>

I haven't tested the above code, but it should work.

Note: The following method will accurately calculate the time difference between the client and the server provided that actual time to send and receive messages is the same or approximately the same. Consider the following scenario:

  Time    Client   Server
-------- -------- --------
Original        0        2
Receive         3        5
Transmit        4        6
Returned        7        9
  1. As you can see, the client and server clocks are 2 units off sync. Hence when the client sends the timestamp request, it records the original time as 0.
  2. The server receives the request 3 units later, but records the receive time as 5 units because it's 2 units ahead.
  3. Then it transmits the timestamp reply one unit later and records the transmit time as 6 units.
  4. The client receives the reply after 3 units (i.e. at 9 units according to the server). However, since it's 2 units behind the server it records the returned time as 7 units.

Using this data, we can calculate:

Sending = Receive - Original = 5 - 0 = 5
Receiving = Returned - Transmit = 7 - 6 = 1
Roundtrip = Sending + Receiving = 5 + 1 = 6

As you can see from above, the sending and receiving times are calculated incorrectly depending upon how much the client and server are off sync. However, the roundtrip time will always be correct because we are first adding two units (receive + original), and then subtracting two units (returned - transmit).

If we assume that the oneway time is always half of the roundtrip time (i.e. the time to transmit is the time to receive, then we can easily calculate the time difference as follows):

Oneway = Roundtrip / 2 = 6 / 2 = 3
Difference = Sending - Oneway = 5 - 3 = 2

As you can see, we accurately calculated the time difference as 2 units. The equation for time difference is always sending - oneway time. However, the accuracy of this equation depends upon how accurately you calculate the oneway time. If the actual time to send and receive the messages is not equal or approximately equal, you'll need to find some other way to calculate the one way time. However, for your purposes this should suffice.