12

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
Tom
  • 1,275
  • 1
  • 18
  • 51
  • 1
    Why would anyone of your customers change their system time? Mostly they are not allowed to change it. Is the specific page shown on every possible computer or on central workstations? – Joshua Mar 26 '13 at 09:53
  • Their system clock will change when the switch over to British Summer Time happens. As it's a real time graph, we need this changeover to happen fluidly on the users display. – Tom Mar 26 '13 at 18:01
  • Windows 7 + Firefox 18.0.1 here. Tried changing system clock both manually and letting it change (timezone change EST -> CEST). Both times the Date showed the correct time without doing anything. – Loamhoof Mar 27 '13 at 16:03
  • @TomHalley, can we assume that your customer's machine(s) will always be in either GMT or BST? Is this is the case, there's a really easy (though not very generic) solution.. – Noyo Mar 28 '13 at 22:10
  • Actually, @TomHalley, are you sure this isn't a problem with the way you're testing this? Have you tried 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 would be setting the clock to 2013-03-31 00:59:00 GMT, checking the hour, waiting a couple minutes, and then checking the hour again. There may not be an issue in your case -- please verify and report? – Noyo Mar 28 '13 at 23:38
  • This coming weekend you can do a live test with PC's changing to summer time (this Sunday at 1:00am GMT) – bart s Mar 29 '13 at 08:15
  • @TomHalley, the Mozilla bug you point to has more to do with time zone changes than time changes. Can you please verify that the Example you've put in your question is really what you mean? I would strongly recommend again that you instead include an example that better demonstrated what you are trying to do (i.e., one where you set the system date and time to just before the real changeover to BST and check the hour before and after said changeover). – Noyo Mar 29 '13 at 14:36
  • Yes, it's not about the user changing the system clock at all. The only problem is a DST time change. I have also tested this to setting the date/time to midnight 31st of march so the computer thinks it's about to run DST and found it still had the same issue – Tom Mar 29 '13 at 18:20
  • @TomHalley, Ah, so the example in your question should maybe be changed to reflect that one should not just change the time and check the hour to test the bug, but the timezone should be changed as well. (Also, the changeover to BST happens just after 00:59, not midnight.) – Noyo Mar 30 '13 at 09:44

5 Answers5

9

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!

Community
  • 1
  • 1
Andy E
  • 338,112
  • 86
  • 474
  • 445
  • I was considering this and hoping there was a solution that was client side, as changing the Date() usage to an API call would mean going through all of the code and changing all usages of Date(). – Tom Mar 22 '13 at 15:03
5

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).

Community
  • 1
  • 1
Antony
  • 14,900
  • 10
  • 46
  • 74
  • I can confirm the same behaviour on Linux. The timezone code in brackets is updated while the offset remains the same. So far this seems like the most practical client-only solution. – Andy E Mar 27 '13 at 11:48
  • @AndyE As I was looking for better timezone data, I found out that different cities use the same abbreviation for different timezones. For example, Brisbane currently use [EST](http://www.timeanddate.com/library/abbreviations/timezones/au/est.html) +10:00 whereas [EST](http://www.timeanddate.com/library/abbreviations/timezones/na/est.html) in the US means -5:00. So unfortunately I cannot get this to work using the abbreviations alone. – Antony Mar 28 '13 at 13:00
  • @AndyE I have changed the answer to use web workers. Now this is a real workaround for the Firefox bug. – Antony Mar 28 '13 at 16:52
  • Nice work! I'm very impressed, though the only potential downside is the asynchronous nature of this approach, but still... great effort on your part :-) – Andy E Mar 28 '13 at 17:18
  • @AndyE It turns out that the `Date()` function is updated whenever a new web worker is created. So we can simply call `Date()` without the `onmessage` event. This effectively removes the asynchronous requirement of the solution. – Antony Mar 29 '13 at 08:22
  • Excellent, this is the best answer of them all. Bravo! – Tom Mar 29 '13 at 18:24
3

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

Sergiu Toarca
  • 2,697
  • 20
  • 24
  • +1 for thinking outside the box, but I don't think this is a practical solution. When I tested this on Ubuntu, it only seemed to work once, although it worked even though Firefox blocked the popup. Subsequent attempts to fetch the date after changing the timezone didn't return the updated time zone. – Andy E Mar 27 '13 at 11:41
  • To be honest, I didn't get that far because I still don't see it as a practical solution, even if it works :-) – Andy E Mar 27 '13 at 15:08
  • It may be possible to ask the user to enable popups. For example, if their app already uses popups for other reasons. Alternatively, there may be ways to circumvent the popup blocker. The OP stressed a client-only solution, and these drawbacks may be worth it. – Sergiu Toarca Mar 27 '13 at 15:19
2

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 :-)

Golo Roden
  • 140,679
  • 96
  • 298
  • 425
1

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!

Noyo
  • 4,874
  • 4
  • 39
  • 41