How to sync a javascript countdown with server tim

2019-01-10 20:12发布

问题:

This question already has an answer here:

  • The best way to synchronize client-side javascript clock with server date 7 answers

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.

回答1:

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;


回答2:

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


回答3:

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.



回答4:

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