Best way to sync client javascript clocks with server date

I have the task of displaying a digital clock (accurate to minutes) on an HTML page in some fixed time zone (MSK or MSD, depending on the current date). I would like not to rely on the clock of the client system, so some synchronization with the server is required. The HTTP server sends a date header in each response, so we can send an AJAX GET or HEAD request to any URL on our site to get the server date, calculate the difference with the client date and use it when updating the clock using setTimeout (). Other problems remain: switching the time zone for daylight settings, delay accounting for very slow connections.

Is any idea for this task the easiest? I would prefer to solve it without server programming.

+47
javascript timezone ajax
Oct 28 '09 at 16:20
source share
7 answers

you must remember the client time between readyState == 2 and readyState == 3 if you intend to use ajax, because the server time will be set somewhere between the time on request and the response received

+7
Oct 28 '09 at 18:00
source share

These two Javascript functions should do the trick for you.

var offset = 0; function calcOffset() { var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); xmlhttp.open("GET", "http://stackoverflow.com/", false); xmlhttp.send(); var dateStr = xmlhttp.getResponseHeader('Date'); var serverTimeMillisGMT = Date.parse(new Date(Date.parse(dateStr)).toUTCString()); var localMillisUTC = Date.parse(new Date().toUTCString()); offset = serverTimeMillisGMT - localMillisUTC; } function getServerTime() { var date = new Date(); date.setTime(date.getTime() + offset); return date; } 

EDIT: deleted ".replace (/ ^ (.) [\ S \ S] /," $ 1 ")".

calcOffset () calculates the offset from the server time and compensates GMT / UTC.

getServerTime () to get the local time offset to match servers using the local time zone.

If calcOffset () takes time to execute, you may lose some second precision. Perhaps the execution time can be taken into account ....

If you are worried that the calculated offset becomes incorrect when the local time or server time changes to daylight saving time or daylight saving time, you can recalculate the litle after each hour of the hour, the system will compensate for changes in the daily time savings. You may need to wait until the clock and the local and server clocks have passed an hour.

The example only works in IE because of "Msxml2.XMLHTTP", I think .....

+37
Oct 29 '09 at 1:24
source share

You can calculate the exact time using NTP (Network Time Protocol) in your codes,

I will try to explain to you:

  • We have ClientTime when sending a request (for example, 4/3/2012 13: 56: 10.123)
  • You send ClientTime to the server
  • We have Time in the opposite direction for the request, I called it RequestTime (for example: it takes 5 seconds).
  • In the server, we calculate the difference time between the server and the client (for example: It ServerTime - ClientTime = ServerClientDifferenceTimeWithRequestTime), you should now this Difference, including the round trip request time in step 3, then you must remove the round-trip time from the Difference
  • Send a server response that includes ServerClientDifferenceTimeWithRequestTime and ServerTime
  • We have Travel time , I called it ResponseTime (for example: it takes 3 seconds)
  • In the client, we again calculate the time difference between the server and the client (for example: It ServerTime - ClientTime = ServerClientDifferenceTimeWithResponseTime), again: now you need this difference, including the response time in the opposite direction in step 6
  • We have time in the client
  • You have to calculate simple equations in the client:

X (SyncedTime) = Now + (ServerClientDifferenceTimeWithRequestTime - RquestTime)

X (SyncedTime) = Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)

Now - ClientTime = RquestTime + ResponseTime =>

Now - (ServerClientDiffRq - RquestTime) = Now - (ServerClientDiffRs - ResponseTime)

if you solve it, you have found this:

ResponseTime = (ServerClientDifferenceTimeWithRequestTime - Now + ClientTime + - ServerClientDifferenceTimeWithResponseTime )/2

and then you can find the synchronized time or server time in the client with this equation:

X (SyncedTime) = Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)

I am showing a simple code, but when you want to write it, remember to use the UTC date and time functions ...

Server side (e.g. php, C #):

PHP:

 header('Content-Type: application/json; charset=utf-8'); $clientTime = $_GET["ct"] * 1; //for php 5.2.1 or up: (float)$_GET["ct"]; $serverTimestamp = round(microtime(true)*1000); // (new DateTime())->getTimestamp(); $serverClientRequestDiffTime = $serverTimestamp - $clientTime; echo "{\"diff\":$serverClientRequestDiffTime,\"serverTimestamp\":$serverTimestamp}"; 

FROM#

 long clientTime = long.Parse(Request.Form["ct"]); long serverTimestamp = (DateTime.Now.Ticks-(new DateTime(1970,1,1) - DateTime.MinValue).Ticks) / 10000; long serverClientRequestDiffTime = serverTimestamp - clientTime; Response.Write("{\"diff\":"+serverClientRequestDiffTime+",\"serverTimestamp\":"+serverTimestamp+"}"); 

Client side (Javascript with Jquery ):

 var clientTimestamp = (new Date()).valueOf(); $.getJSON('http://yourhost.com/getdatetimejson/?ct='+clientTimestamp, function( data ) { var nowTimeStamp = (new Date()).valueOf(); var serverClientRequestDiffTime = data.diff; var serverTimestamp = data.serverTimestamp; var serverClientResponseDiffTime = nowTimeStamp - serverTimestamp; var responseTime = (serverClientRequestDiffTime - nowTimeStamp + clientTimestamp - serverClientResponseDiffTime )/2 var syncedServerTime = new Date((new Date()).valueOf() + (serverClientResponseDiffTime - responseTime)); alert(syncedServerTime); }); 
+28
Apr 03 '13 at
source share

I found that the @ mehdi-yeganeh algorithm above did not give me useful results, but the idea is sound: use the NTP algorithm (or at least the weak version) to synchronize the server and client clocks.

This is my latest implementation, it uses the server response headers if they are available for extra accuracy (please correct me if I am wrong, my own tests say that it is pretty accurate).

browser side (javascript):

 // the NTP algorithm // t0 is the client timestamp of the request packet transmission, // t1 is the server timestamp of the request packet reception, // t2 is the server timestamp of the response packet transmission and // t3 is the client timestamp of the response packet reception. function ntp(t0, t1, t2, t3) { return { roundtripdelay: (t3 - t0) - (t2 - t1), offset: ((t1 - t0) + (t2 - t3)) / 2 }; } // calculate the difference in seconds between the client and server clocks, use // the NTP algorithm, see: http://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm var t0 = (new Date()).valueOf(); $.ajax({ url: '/ntp', success: function(servertime, text, resp) { // NOTE: t2 isn't entirely accurate because we're assuming that the server spends 0ms on processing. // (t1 isn't accurate either, as there bound to have been some processing before that, but we can't avoid that) var t1 = servertime, t2 = servertime, t3 = (new Date()).valueOf(); // we can get a more accurate version of t2 if the server response // contains a Date header, which it generally will. // EDIT: as @Ariel rightly notes, the HTTP Date header only has // second resolution, thus using it will actually make the calculated // result worse. For higher accuracy, one would thus have to // return an extra header with a higher-resolution time. This // could be done with nginx for example: // http://nginx.org/en/docs/http/ngx_http_core_module.html // var date = resp.getResponseHeader("Date"); // if (date) { // t2 = (new Date(date)).valueOf(); // } var c = ntp(t0, t1, t2, t3); // log the calculated value rtt and time driff so we can manually verify if they make sense console.log("NTP delay:", c.roundtripdelay, "NTP offset:", c.offset, "corrected: ", (new Date(t3 + c.offset))); } }); 

server side (php, but could be anything):

Your server on the "GET / ntp" route should return something like:

 echo (string) round(microtime(true) * 1000); 

If you have PHP> 5.4, you can save the microtime () call and make it more accurate with:

 echo (string) round($_SERVER['REQUEST_TIME_FLOAT'] * 1000); 

Note

This method can be considered as a kind of ghetto, there are other answers related to stack overflow that will help you find the best solution:

  • How to synchronize javascript countdown with server time
  • Synchronize JS time between multiple devices
  • It is noteworthy that this solution has been proposed several times: https://github.com/NodeGuy/ServerDate . It sounds like a little trickier, but it's better to ensure accuracy.
+21
Apr 09 '14 at 17:06
source share

I would request an update only from the server every 30 or so if you only need accuracy to the minute. Do not rely on client time at all, but use their system clock to maintain clock accuracy between updates. I think you answered your question?

This will help if we better understand what you are actually trying to do.

If you just want the clock to display the time on the server, which then adjusts to a specific time zone, do this with clients using offsets. Manage DST in time zones, this is applicable using the date you get from the server. If you want to determine the delay, you will probably need a small script on the server to calculate the difference. But, as above, this will help to better understand the problem. If accuracy is only up to a minute, latency seems less critical.

0
Oct 28 '09 at 16:24
source share

Thanks to @Mehdi Yeganeh and @Fedearne. I implement my function to use both logic and its operation.

https://gist.github.com/ethaizone/6abb1d437dbe406fbed6

0
Mar 08 '16 at 11:22
source share

I would synchronize the time during initialization with the internet time server.

http://tf.nist.gov/service/its.htm

-3
Oct 28 '09 at 16:51
source share



All Articles