Need workaround for Firefox Date() bug

2020-02-26 06:50发布

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

5条回答
等我变得足够好
2楼-- · 2020-02-26 07:32

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

查看更多
家丑人穷心不美
3楼-- · 2020-02-26 07:41

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!

查看更多
干净又极端
4楼-- · 2020-02-26 07:41

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

查看更多
淡お忘
5楼-- · 2020-02-26 07:49

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!

查看更多
Deceive 欺骗
6楼-- · 2020-02-26 07:54

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

查看更多
登录 后发表回答