How to sync a javascript countdown with server time [duplicate]
Asked Answered
E

4

23

I am building a site which has times and prices which tick down. The thing I am most concerned with is syncing time so that it is as accurate as possible across all clients.

Currently, I am sending the client the number of milliseconds left which is then used to fuel the countdown timer, but due to transfer and rendering delays, this can be off by several seconds even with 2 browsers on the same computer.

Is there a way to sync the client's javascript time and server time, or am I just going to have to deal with this slight lag?

If only there was a way to accurately measure the time difference between the server sending the data and it being received and rendered by the client.

Equites answered 18/3, 2011 at 20:52 Comment(2)
what do you think about fueling the count down timer via an ajax call after the page has loaded, you could initially not display the counter by hiding it, then display on ajax success. The request would be much quicker since your not doing a full page post back.Micrometer
@The Muffin Man the ajax call also depends on the amount of traffic/load the server has.. this will also lead to delay.Pasta
R
23

Even though the time on the server and client is going to be different, the rate at which time changes should essentially be same. I would send the remaining time down to the client, let the client then add that time to the current time, and then have the client calculate the countdown from that. For example:

var timeRemaining = [rendered on page load or queried by ajax]; // in milliseconds
var endTime = new Date(new Date().getTime() + timeRemaining);

// Put this in a setInterval, or however you currently handle it
var countdown = (endTime.getTime() - new Date().getTime()) / 1000;
Reverend answered 18/3, 2011 at 21:2 Comment(4)
Note that if you populate timeRemaining on page load, sometimes the page is cached by the web browser, and this cached version will be rendered if your user navigates away from the page and to returns to it via the back button. In this case the timer will appear to not have moved at all (because timeRemaining is remains cached and unchanged). Tricky indeed.Blasting
I cant understand this at all what do you mean rate of change of time? when server calculates the time remaining then send it where is the delay for the response delay?Ominous
@Doggynub rate of change of time means 1 second on client is the same as 1 second on server.Staff
The only issue here is if there is a "Master" countdown that should be a benchmark for "follower" countdowns. Say you have a contestant who ahs to answer a question in 1:00, and viewers watching him want to track his countdown. Server delays could implicate a 1/2 second difference. Am I right?Amphidiploid
K
16

There is a way to synchronize a client with the server's time. I wrote a library that does just this: ServerDate.

Here's part of the README:

You can use ServerDate as you would use the Date function or one of its instances, e.g.:

> ServerDate()
"Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

> ServerDate.now()
1344900478753

> ServerDate.getMilliseconds()
22

There is also a new method to get the precision of ServerDate's estimate of the server's clock (in milliseconds):

> ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
"Tue Aug 14 01:01:49 2012 ± 108 ms"

You can see the difference between the server's clock and the browsers clock, in milliseconds:

> ServerDate - new Date()
39
Kasten answered 14/8, 2012 at 19:54 Comment(4)
Glad I found your work. This helps me a lot especially working with countdown that has to be synced with everybody else. I was thinking a server time as based but not sure how to properly implement it, but you did. Hands down. Would it be possible to add callbacks like if the local time is out sync or when its already been synced?Lemus
Feel free to create an issue on GitHub and let's discuss it there.Kasten
Please can you clarify if ServerDate.js addresses this comment's concern around page caching?Cheesecloth
It does handle page caching.Kasten
D
1

You can measure the time the full server roundtrip takes and divide by two to get a good estimate for the time difference. Be careful: it's not guaranteed that IP packages take the same route in both directions, but the propability is quite high.

You can use Date.getTime() if millisesonds resolution is enough for you.

Dorman answered 18/3, 2011 at 20:56 Comment(1)
Plus an offset for whatever difference the server and client system clocks have.Classic
C
0

The solution to this is Javascript – it can access time zone settings on the client. Unfortunately it can only get you time zone offsets (specified in minutes) for specific dates, no time zone name. So to pinpoint the correct time zone we also need to know if daylight saving time (DST) is being employed – this is the client side part of the solution:

var now = new Date();
var later = new Date();
// Set time for how long the cookie should be saved
later.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
// Set cookie for the time zone offset in minutes
setCookie("time_zone_offset", now.getTimezoneOffset(), later, "/");
// Create two new dates
var d1 = new Date();
var d2 = new Date();
// Date one is set to January 1st of this year
// Guaranteed not to be in DST for northern hemisphere,
// and guaranteed to be in DST for southern hemisphere
// (If DST exists on client PC)
d1.setDate(1);
d1.setMonth(1);
// Date two is set to July 1st of this year
// Guaranteed to be in DST for northern hemisphere,
// and guaranteed not to be in DST for southern hemisphere
// (If DST exists on client PC)
d2.setDate(1);
d2.setMonth(7);
// If time zone offsets match, no DST exists for this time zone
if(parseInt(d1.getTimezoneOffset())==parseInt(d2.getTimezoneOffset()))
{
setCookie("time_zone_dst", "0", later, "/");
}
// DST exists for this time zone – check if it is currently active
else {
// Find out if we are on northern or southern hemisphere
// Hemisphere is positive for northern, and negative for southern
var hemisphere = parseInt(d1.getTimezoneOffset())-parseInt(d2.getTimezoneOffset());
// Current date is still before or after DST, not containing DST
if((hemisphere>0 && parseInt(d1.getTimezoneOffset())==parseInt(now.getTimezoneOffset())) ||
(hemisphere<0 && parseInt(d2.getTimezoneOffset())==parseInt(now.getTimezoneOffset()))) { setCookie("time_zone_dst", "0", later, "/"); } // DST is active right now with the current date else { setCookie("time_zone_dst", "1", later, "/"); } }

You save the results as cookies, which can be accessed by your PHP script. You should include the above code on at least the first page a user accesses – I include it on every page to recognize (and adapt to) changes, even if such changes during a session are unlikely.

In PHP you can extract a valid time zone with a new function named timezone_name_from_abbr, available since PHP 5.1.3 – it either takes a time zone abbreviation or a combination of time zone offset (in seconds) and daylight saving time, and we have the latter combination:

$time_zone_name = timezone_name_from_abbr(", -$_COOKIE['time_zone_offset']*60, $_COOKIE['time_zone_dst']);

This will give you a correct time zone name for the user, if the data in the cookies is valid – note that there are many “duplicate” names, for example “Europe/Berlin” and “Europe/Zurich”, which have the exact same time zone settings (at least for now), and you may get either one of them for the appropriate offset and DST variables. The list of time zone names can be found in the List of supported time zones on php.net.

Creating date strings with a given time zone With the name of the user’s time zone you can now use the PHP classes DateTimeZone and DateTime to finally create date strings with the correct time zone:

// Create time zone class
$time_zone_class = new DateTimeZone($time_zone_name);
// Create new date class with a given date
// Notice that the provided date will be regarded as being in the
// default time zone and converted accordingly
$new_date = new DateTime(‘2007-02-14 15:30:00′, $time_zone_class);
// Print date with the user’s time zone echo $new_date->format(‘Y-m-d H:i:s’);

That’s it!

Source: http://togl.me/eE2

Cazzie answered 19/2, 2012 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.