How to synchronise a client webpage timer with the server - javascript

What is the best way to synchronise the time on a webpage with the server?
My webpage needs to start a countdown at the same time for all users, and and end at exactly the same time to prevent any one user having a slight time advantage.
My problem is similar to this question but the accepted answer helps but does not fully answer my concerns: how-to-sync-a-javascript-countdown-with-server-time
I use Ajax after pageload to get the server time, but am I guaranteed over 15 minutes that the countdown will end at exactly the same time for each client?
Even if the timers accurately measure the time, there could still be a discrepancy of just under 1 second between client pages caused by disregarding the milliseconds for the setInterval - is there any way to overcome this?

The accepted answer is good and helped inspire me as I wrote a library to solve this problem. The library yields more precise answers by looking at the load times of itself, rather than the whole page (as done with performance.timing above) and then gets even better precision by following with a series of 10 XMLHttpRequests. Also, addressing your second concern, my library doesn't disregard the milliseconds (as does the accepted answer).
The library is called ServerDate and is freely available.
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

In modern browsers, you can achieve this by assigning a timestamp to a JavaScript variable, and use the Performance object to calculate the exact time.
Example:
var tsp = new Date('Sun Feb 19 2012 17:55:14 GMT+0100 (CET)'); // "Timestamp"
window.onload = function() {
var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
tsp.setTime(tsp.getTime() + performance.timing.loadEventStart - performance.timing.navigationStart
// after window.onload, you're sync with the server
// Example of timer:
setInterval(function() {
tsp.setSeconds(tsp.getSeconds() + 1);
document.title = tsp.toString();
}, 1000); // 1000 ms = timer may be off by 500ms.
};
For more information on this object, have a look at the MDN's article.
A demo is provided here.

Ideally your solution would involve the server sending out the signal that the submit form is open to all clients at the same time. For that you could use web sockets if you have no problem with excluding people with older browsers. There are also fallbacks using long polling for those browsers.
I am not sure how well websockets do together with PHP though.
I've only ever used socket.io together with node JS. With that solution it would be trivial to set a server-side timeout and notify all clients at the same time when it's complete. It automatically detects the browser support and chooses a method that works best for a given browser.
Using this solution the clients will only ever allow submissions when the server has told them it is ready. As long as the server you submit to performs validation you should be fine.

Related

How does UTC work with Javascript and computers with wrong times?

I have been writing some JavaScript code that relies upon universal time. I have been doing this online with two computers. One of which is 24 minutes behind the other.
Example:
Computer 1: 25/07/2020, 21:57 Computer 2: 25/07/2020, 22:21
When both computers enter a UTC number they are still the equivalent of 24 minutes apart.
Computer 1: 1595710054892 Computer 2: 1595711497605
This difference in time is causing problems with my programme as it relies upon timed notifications.
Is there anyway to correct for this or will I just have to hope that computers that use my JavaScript code will all have the same time within their respective timezone?
If you can't trust the clock on the computer (which is, frankly, shocking for a network-connected system in 2020) then you need to get the current time from somewhere else.
The standard way to do this would be to use the Network Time Protocol.
A quick Google turns up this JavaScript implementation of an NTP client:
var ntpClient = require('ntp-client');
ntpClient.getNetworkTime("pool.ntp.org", 123, function(err, date) {
if(err) {
console.error(err);
return;
}
console.log("Current time : ");
console.log(date); // Mon Jul 08 2013 21:31:31 GMT+0200 (Paris, Madrid (heure d’été))
});
If you're dealing with JS in a browser, you won't be able to use the NTP protocol directly so you would need to proxy the request via some server-side code which would lose some accuracy (but assuming a reasonable network connection, that would be in the order of a few seconds rather than 10s of minutes).

Need workaround for Firefox Date() bug

I'm working on a canvas graph that's updated in real time with information we're displaying to a customer, and were in the process of preparing for the DST change on the clocks. One of our requirements is for the graph to carry on functioning as usual without the need for the customer to refresh the page when the clocks switch over.
While working on this problem, I found out about this bug with Firefox:
https://bugzilla.mozilla.org/show_bug.cgi?id=127246
Basically the Date() object in JavaScript doesn't update in Firefox if the system time is changed without having to close the browser/tab, and as we're querying an API using the system clock, this is a pretty major problem.
I'm assuming it's not fixed as the ticket is still marked as 'NEW', and I'm also pretty sure it's this that's causing the problem rather than another part of my code, so how can i get the current time of the system clock after it changes in Firefox without having to refresh the page?
FYI the version of Firefox I'm using is 19.0.2
Thanks in advance
Example
Set system clock to 12:00 and open web app...
var currentHour = new Date().getHours() //returns 12
Set system clock to 13:00 without reopening web app..
var currentHour = new Date().getHours() //returns 12
You can't ever rely on the client-side to have the correct date/time set anyway. The only workaround I can think of is to request the current time from another source, e.g. the server.
If you don't want to bug your own server you could find a public API that returns a timestamp, like some kind of Time API, or a service with reliable uptime such as eBay's Client Alerts API for instance:
http://clientalerts.ebay.com/ws/ecasvc/ClientAlerts?callbackname=hello&callname=GetPublicAlerts
hello({"Timestamp":"2013-03-22T14:43:21.757Z","Ack":"Failure","Errors":[{"ShortMessage":"Missing required input element.","LongMessage":"Required input element is missing from the request.","ErrorCode":"1.19","SeverityCode":"Error","ErrorParameters":[{"Value":"ChannelDescriptor","ParamID":"0"}],"ErrorClassification":"RequestError"}],"Build":"E809_CORE_BUNDLED_15739296_R1","Version":"809"});
Ignore everything and just get the UTC timestamp. Just make sure you're not bashing the hell out of some server for data you don't really need!
Use Web Workers
Instead of creating a new window as in Sergiu Toarca's answer, create a new web worker every time you need an update. Firefox would update the Date() object whenever a new web worker is generated.
function currDate() {
var blob = new Blob([""]),
blobURL = window.URL ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob),
worker = new Worker(blobURL);
worker.terminate();
return new Date();
}
You can use it like a normal Date() object:
currDate().getHours(); // Gives you an updated hour
See DEMO (Works on Firefox 19).
There is a simple (but very hacky) workaround for this problem. You can create a new window (which for some reason resets the cache of the current window), get the date from there, and then immediately close the window.
var getRealDate = function() {
var w = window.open();
var ret = new Date();
w.close();
return ret;
};
See it work on jsfiddle. Click the button, then change your timezone, then click the button again, and you will get an updated value.
Note: Only tested in Firefox 19
As you are talking about real-time updates of the canvas I assume that you are using some kind of push technology, such as making use of web sockets, or some fake push technology such as AJAX long polling.
However, as you can not rely on the client-side time anyway (as was mentioned in the other answer), why not just use your real-time push data packages to include the current time?
This way you can kill two birds with one stone (sorry for the martial expression, but that's how they say ;-)):
You have one central clock you can rely on: Your server.
You make use of your existing data update infrastructure and do not need something else on top.
Clients can set their clocks to whatever they want, they will always the correct data.
All your clients need to do is to get the timezone they are in initially, and then add or subtract the difference to the timezone that is being delivered by the server. E.g., if your client is on UTC+1 and your server is UTC+4, then simply subtract 3 hours from each timestamp your server delivers.
As DST changes only appear twice a year, you can even hard-code this into your client and use two different addition / subtraction algorithms. Which one you have to use you can decide depending on the date part of the time stamp the server sends to you.
This way you should have solved all your problems, it works in every browser, and is independent of any time settings of the client.
Hope this helps :-)
Here's a super-simple solution for the OP's specific situation, given that the following assumptions I've made (based on what's written in his question and comments) are correct:
the graph is only for one customer
the graph will be loaded primarily on Firefox (versions that have the same referenced bug)
the customer's machine(s) is/are all based in GMT (which becomes BST when the clocks change)
the machine clock(s) is/are reasonably accurate
the customer doesn't go changing the machines' clocks will-nilly.
If the above are true (possibly not even all of them), this becomes pretty simple. Because you'd really only be worried about two time zones, GMT and BST, you can adapt your example as follows:
Add this bit of code at load time / graph initialization:
// given a date object, returns the actual hour (works for GMT/BST only)
var getDisplayHour = (function() {
var initiallyGMT = (new Date().toString().indexOf('BST') === -1);
return function ( date ) {
var isGMT = (date.toString().indexOf('BST') === -1);
var offset = initiallyGMT - isGMT;
return date.getHours() + offset;
}
})();
Set system clock to 12:00 and open web app...
var currentDisplayHour = getDisplayHour( new Date() ); // returns 12
Set system clock to 13:00 without reopening web app..
// the referenced bug keeps the same time, but it successfully changes the time zone, so:
var currentDisplayHour = getDisplayHour( new Date() ); // returns 13
Tested on FF 19.0.0.2 on Mac and Windows 7.
Note: Since I wasn't really able to reproduce the OP's issue, and considering the cited use case, I'm not even sure there's a need for any of these workarounds at all. One might expect a more accurate test for the OP's use case to involve changing both the time AND the zone. E.g. not just 12:00 -> 13:00, but 12:00 GMT -> 13:00 BST. An even more accurate simulation of the DST changeover would be to set the clock to 2013-03-31 00:59:00 GMT, check the new Date().getHours(), wait a couple minutes, and then to check the hour again.
But, as I said, I haven't been able to reproduce the cited bug this myself, so I could definitely be wrong (in which case I'll amend or remove this answer).
Hope this helps, anyway!

Blackberry browser Javascript Time DST issues

We are targeting Blackberry OS 6 and 7 devices, and are having issues with Javascript and daylight saving time. The behaviour we're seeing for different devices/OS versions is either:
keeps DST setting till end of month (so switches at 1-Nov instead of 28-Oct for Europe this year)
uses the same DST setting/time zone offset for the whole year (so after 28-Oct the time zone will be CET (+100), and before 28-OCt it will be CEST (+200), for the whole year)
More specific for different devices/versions:
9800 - 6.0.0.246: uses same offset for all dates
9780 - 6.0.0.285: uses same offset for all dates
9780 - 6.0.0.668: switches at end of month
9700 - 6.0.0.668: switches at end of month
9360 - 7.0.0.530: switches at end of month
Is anyone aware of these issues and/or a workaround?
I have found this Blackberry issue, which explains the 'same offset for all dates' issue, and I think they fixed it in the wrong way: http://supportforums.blackberry.com/t5/Web-and-WebWorks-Development/Javscript-GMT-Offfset-not-working-in-BB6-0-Devices-Non-Torch/td-p/815883
We also developed a test page, which reveals the issue by executing some simple document.write(new Date(timestamp)) statements, available here: http://bit.ly/QhJOIC
One option if the web page is for online use only: then you could make a ajax call back to the server to get proper offset for this user. This would then use a libary of your choice for providing the time zone and DST information. Just return user location infromation to the server.

is epoch time the same on the same machine with diffent scripts/programs

I want to use shell to get epoch time
and later use javascript on a html page to get another epoch time
and then get the difference between them
but I'm afraid that the epoch time may not be synchronized among different scripts
so this difference is useless
so I want to know, if at the very same time, I use shell and javascript to get epoch tiem
will the result be the same or not?
if not, how big is the difference?
thanks!
If you mean number of seconds since Unix epoch (1970-01-01T00:00:00Z), it is governed by this very definition. The only differences you should be able to see are caused by:
different times of invocation of the system call that returns it*);
unsynchronized clocks on different systems.
and possibly also:
unsynchronized clocks on different processor cores/physical processors;
implementation dependent handling of the function that returns current time (e.g. JS engine implementation might possibly cache the value for a short time as not to have to do the actual syscall, although I would doubt this).
Depending on the time resolution you need, some of these are not a problem. My guess is, that if you don't need granularity finer than 1s, you should be more than fine (on the same machine).
*) also note, that on single core system, you can't really get the same time (at least with the ns resolution) from different syscalls, unless the kernel caches it, simply because they have to happen one after another.
According to ECMA-262 section 15.9.1.1:
Time is measured in ECMAScript in milliseconds since 01 January, 1970
UTC. In time values leap seconds are ignored. It is assumed that there
are exactly 86,400,000 milliseconds per day.
So, yes, every JavaScript implementation that adheres to standard must return exactly same values, taking care of any physical clock quirks by itself. Barring wrong set up of system clock you will have same value everywhere.
Note that definition of "epoch" and "seconds since" in other languages and systems could be different (at very least most other systems use seconds, not milliseconds and most often take leap seconds in account), so you can't guarantee that JS time, even divided by 1000 will match timestamp from another platform or OS.

Is it safe to compare JavaScript's getTime() across different systems?

JavaScript's getTime() returns "the number of milliseconds since 1 January 1970 00:00:00 UTC".
Can I rely on this being similar across different machines? I don't need it to be accurate to the millisecond, just to a few seconds.
Or do I need to use an external time service API, as in this question?
Where does JavaScript get the current time from - is it dependent on the machine's clock?
Can I rely on this being similar across different machines?
No.
Where does JavaScript get the current time from
The system datetime on which this javascript runs.
Or do I need to use an external time service API, as in this question?
You could use the server's time and send it to the client.
Javascript is definitely going to use the internal clock of the machine (where else could it possibly get this information?).
Whether it is safe depends on what you are writing and for what reason. If you do decide to use it to compare it across machines, make sure it is very fault taulerant, as this can easily be messed with.

Categories