Synchronize with the Server's Clock in the Browser

two hourglasses

Introduction

Sometimes it's useful to know the exact time (within 100 ms) of the clock on the server from within the browser. This can be used to synchronize multiple user's actions with each other, for example. I found a need for this when I created a Pomodoro Technique timer for my personal productivity company.

But how to accomplish this? Network Time Protocol (NTP) is one of the oldest protocols used on the Internet but is too heavy to run in the browser. I needed something lighter that would still do the job well enough. When I didn't find an existing library to suit me I started doing research. After reading "Probabilistic clock synchronization" by Flaviu Cristian Cristian, F. (1989), "Probabilistic clock synchronization", Distributed Computing (Springer) 3 (3): 146–158, DOI:10.1007/BF01784024, I rolled up my sleeves and started coding.

The result is ServerDate, available for free on GitHub. It creates a new object in the browser named ServerDate which has the same API as the JavaScript Date object minus its mutable methods. At regular intervals the library queries the server and then makes an educated guess about the clock's current time, based on how long it took to receive the response.

In this article I explain how the implementation works.

Implementation

Every so often (by default once an hour, as defined by ServerDate.synchronizationIntervalDelay), the library sends a query to the server (using XMLHttpRequest) asking for the current time. Simple code to run on the server is provided, for both Node.js and PHP, which responds with the server's current timestamp.

This is where it gets interesting: We can't just use the timestamp from the server because there is a delay as it travels across the Internet from server to client, so it will be out of date by the time the browser receives it. So first we need to compute the precision of the timestamp (available as ServerDate.getPrecision()) based on the latency of the response. This is computed in milliseconds:

precision = (responseTime - requestTime) / 2

The lower the latency of the response, the better the precision. In order to get the best precision we can, the library sends 10 requests to the server and then uses the one with the lowest latency. It then estimates the time on the server, where responseTime is the time at which it received the response:

serverTime = serverResponse + precision - responseTime

Note that we record responseTime as part of our XMLHttpRequest as soon as we receive the headers of the response (this.readyState === this.HEADERS_RECEIVED) rather than waiting for the whole body to be parsed in order to get the most accurate value possible.

If the ServerDate object is being used to display the time on the web page, and it changes significantly as a result of the server synchronization, then the time will appear to jump abruptly in the UI. To smooth out this effect the library has a configurable parameter (ServerDate.amortizationRate) which is used to slow the rate at which the ServerDate object is changed from its current value to the correct one.

Are you using ServerDate in one of your projects? Please tell me about it in a comment below.

View or Post Comments