Need workaround for Firefox Date() bug - javascript

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!

Related

Moment and new Date() not displaying local time

I want to display the local date of the user, but nothing is working for me. It always returns the UTC time.
I have tried:
This returns UTC - also in here offset comes as zero.
let visitDate = moment.utc().format();
let offset = moment().utcOffset();
let visitDate1 = moment.utc(visitDate).utcOffset(offset)
This returns UTC
let visitDate = new Date()
let visitDate1 = moment(visitDate).local().format('MM-DD-YYYY hh:mm:ss');
This returns UTC
let visitDate = new Date()
let visitDate1 = visitDate.toLocaleDateString()
I have tried several methods, but it doesn't matter what I do, I always get UTC time. If I try on localhost then it displays the correct time, but once I host the page it displays UTC.
How can I transform to local?
moment().local() uses the timezone of the local machine, that's why it works in localhost
if you know it, I would specify the timezone:
moment.tz("America/Los_Angeles").format()
There seem to be several possible points of failure. I'll list the ones I think of below, and you can assess whether they're relevant to your setup.
1) The code that manipulates the date is executed on the server, not locally
Most of our Javascript code is written to execute in the user's browser, so that's the default assumption. If that assumption is wrong in this case, and the code is being executed on the server, then "local" means "on the server." Your server should be running with UTC time, which could produce the results you're seeing.
2) The user is running a browser set to UTC
If the browser you're using for testing is set to consider UTC as local time, it'd produce the results you're seeing. Since you're probably using the same machine for localhost and for testing, it's an unlikely source of the problem...but worth noting nonetheless.
3) Changing how the date is displayed does not change how the date is stored
Many of the tools we have for setting/changing the time zone affect how the date is displayed. However, Date objects in Javascript are stored using Unix Time (in milliseconds), which is UTC. When you create a Date object--even with a time zone specified--the behind-the-scenes representation will still be an integer (representing a number of milliseconds) and based on UTC. If you're checking the stored value rather than the displayed value, when you're testing, then there's a good chance you'll always see UTC. However, the work you're doing with the moment library should have the date formatted correctly. If you're checking the moment object, you should be seeing the time zone you expect to see.
If none of these three possible failure points applies to your context, then perhaps they spark an idea for you. (The third one, especially, feels like it might be on the right track even if it's not what's happening in your case.)

Is there a way to get the actual time in UST (ignoring user settings) in React Native?

I'm currently working on a bug where the user manually sets their timezone and then manually sets the time within that timezone (say, 3 hours behind). This causes the system to use the user's time (which is 3 hours behind UST). Due to this, any calls to a Javascript or React Native library will return a time that is 3 hours behind the actual time. This causes issues when dealing with API calls to my server which returns the actual time in UST
I've tried using Date objects, the I18n library, and just about everything in between. I'm trying to find a universal fix for both Android and iOS since this is a part of my cross-platform codebase.
Any help would be greatly appreciated!
The libraries get the time from the client, how about getting the time from an external source? You can use this API: https://timezonedb.com/api
Another possibility is storing and updating a time offset, so you can calculate the actual time from the current time that is set.

JS Timezones not current

I have just created a blog script, but when I add a comment.
The timestamp in the database is 2014-07-29 18:55:00 even that the clock on my PC is 2014-07-29 20:55:00.
So I would like to change the time according to the timezone.
So I tried with this code (where timestamp is 2014-07-29 18:55:00):
var UTC = moment.tz(timestamp, "UTC");
timestamp = UTC.clone().tz(timezone).format('YYYY/MM/DD H:mm:ss');
Note: window.timezone is set using the following code:
var tz = jstz.determine();
var timezone = tz.name();
The time I want to get out is 2014/07/29 20:55:00, but I get this out: 2014/07/29 17:53:47
I am using the following libraries for this above code:
https://bitbucket.org/pellepim/jstimezonedetect
http://momentjs.com/timezone/
http://momentjs.com/
Hope that someone understands whats going on.
NOTE: I live in Europe/Denmark which have the timezone UTC/GMT +2 hours
In addition to script, moment-timezone requires data to function. If you don't have the data loaded, in version 0.1.x it will use the local time zone - as if you just called moment() without any tz specified. This has been fixed for the upcoming 0.2.0 release, such that it gives an error instead of silently doing the wrong thing.
Normally, you could use the data builder to just provide data for the time zones you were interested in. However, it is currently offline because the format of the data changed in the last release and the author has not yet had time to complete the required updates.
In the meantime, you can use one of the "data-included" versions, downloadable at the top of the main page - for example, use moment-timezone-2010-2020.js instead of just moment-timezone.js.
Also, you since you're using jsTimeZoneDetect - you should test the value returned by jstz.determine() to make sure it is indeed the time zone you are expecting. The +2 offsets are notoriously difficult to test for. See some of the known issues.
You could set the timezone
moment().tz("Europe/Denmark").format();

Javascript - overriding new Date() behavior to offset GMT

I'm developing a website that uses Comet to transmit data back to web clients. My application is very time sensitive, I have a graph displaying points added every second.
Since the web application is Comet driven there is no real need for the client to handle dates, it should only use the server timestamp to display information. i.e. a plotted point on the graph should display in the tooltip the server timestamp, regardless of the user's timezone.
I think my best approach would be to retrieve the server's timestamp using REST. Then measure the timezone offset between the server and client time, add/deduct the difference and use it as the client's timestamp for display purposes.
Is there a way to override the default behavior of new Date() to result in me having the server's timestamp as the local?
Many thanks.
I wrote the library TimeShift.js that allows overriding the Date constructor and setting the current time and time zone. I wrote it for testing purposes, but it could be used for other uses as well.
Be sure to check the caveats of the current library. It currently only supports a fixed offset to GMT, so DST changes are not supported.
just redefine it, it should work fine:
if(Date) {
try{
Date = null;
Date = function() {
console.log("The more things change, the more they stay the same!");
}
Date();
} catch(exeption) {
console.log("Couldn't override Date object.");
}
}

How to synchronise a client webpage timer with the server

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.

Categories