12

我正在制作一个画布图表,该图表使用我们向客户显示的信息实时更新,并且正在为时钟上的 DST 更改做准备。我们的要求之一是图表能够像往常一样继续运行,而无需客户在时钟切换时刷新页面。

在解决这个问题时,我发现了 Firefox 的这个错误:

https://bugzilla.mozilla.org/show_bug.cgi?id=127246

基本上 JavaScript 中的 Date() 对象不会在 Firefox 中更新,如果系统时间发生更改而无需关闭浏览器/选项卡,并且当我们使用系统时钟查询 API 时,这是一个相当大的问题。

我假设它不是固定的,因为票仍然标记为“新”,我也很确定这是导致问题的原因,而不是我的代码的另一部分,所以我怎样才能获得系统的当前时间在 Firefox 中更改时钟后无需刷新页面?

仅供参考,我使用的 Firefox 版本是 19.0.2

提前致谢

例子

将系统时钟设置为 12:00 并打开 Web 应用程序...

var currentHour = new Date().getHours() //returns 12

在不重新打开网络应用程序的情况下将系统时钟设置为 13:00。

var currentHour = new Date().getHours() //returns 12
4

5 回答 5

9

无论如何,您永远不能依赖客户端来设置正确的日期/时间。我能想到的唯一解决方法是从另一个来源(例如服务器)请求当前时间。

如果您不想破坏自己的服务器,您可以找到返回时间戳的公共 API,例如某种Time API,或具有可靠正常运行时间的服务,例如 eBay 的 Client Alerts API:

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"});

忽略所有内容,只获取 UTC 时间戳。只要确保您不会因为您并不真正需要的数据而将某些服务器撞到地狱!

于 2013-03-22T14:49:47.710 回答
5

使用网络工作者

与其在Sergiu Toarca 的回答中创建一个新窗口,不如在每次需要更新时创建一个新的网络工作者。Date()每当生成新的网络工作者时,Firefox 都会更新该对象。

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();
}

您可以像使用普通Date()对象一样使用它:

currDate().getHours(); // Gives you an updated hour

请参阅演示(适用于 Firefox 19)。

于 2013-03-26T21:21:17.547 回答
3

对于这个问题,有一个简单(但非常hacky)的解决方法。您可以创建一个新窗口(由于某种原因会重置当前窗口的缓存),从那里获取日期,然后立即关闭窗口。

var getRealDate = function() {
    var w = window.open();
    var ret = new Date();
    w.close();
    return ret;
};

看到它在jsfiddle上工作。单击按钮,然后更改您的时区,然后再次单击按钮,您将获得更新的值。

注意:仅在 Firefox 19 中测试

于 2013-03-27T07:58:13.237 回答
2

当您谈论画布的实时更新时,我假设您正在使用某种推送技术,例如使用 Web 套接字,或者一些虚假推送技术,例如 AJAX 长轮询。

但是,由于您无论如何都不能依赖客户端时间(如另一个答案中所述),为什么不使用实时推送数据包来包含当前时间?

这样你就可以用一块石头杀死两只鸟(对不起,军事表达,但他们就是这么说的;-)):

  • 您有一个可以依赖的中央时钟:您的服务器。
  • 您可以利用现有的数据更新基础设施,并且不需要其他东西。
  • 客户可以将他们的时钟设置为他们想要的任何时间,他们将始终获得正确的数据。

您的客户需要做的就是获取他们最初所在的时区,然后将差值添加或减去服务器提供的时区。例如,如果您的客户端使用 UTC+1 而您的服务器使用 UTC+4,那么只需从服务器提供的每个时间戳中减去 3 小时。

由于 DST 更改每年仅出现两次,您甚至可以将其硬编码到您的客户端中并使用两种不同的加法/减法算法。您必须使用哪一个,您可以根据服务器发送给您的时间戳的日期部分来决定。

这样你应该已经解决了所有问题,它适用于每个浏览器,并且独立于客户端的任何时间设置。

希望这可以帮助 :-)

于 2013-03-26T19:31:32.127 回答
1

鉴于我所做的以下假设(基于他的问题和评论中所写的内容)是正确的,这是针对 OP 特定情况的超级简单解决方案:

  • 该图仅适用于一位客户
  • 该图将主要在 Firefox 上加载(具有相同引用错误的版本)
  • 客户的机器都基于 GMT(时钟改变时变为 BST)
  • 机器时钟相当准确
  • 客户不会随意更改机器的时钟。

如果上述情况属实(甚至可能不是全部),这将变得非常简单。因为你真的只担心两个时区,GMT 和 BST,你可以调整你的例子如下:

在加载时/图形初始化时添加这段代码:

// 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;
  }
})();

将系统时钟设置为 12:00 并打开 Web 应用程序...

var currentDisplayHour = getDisplayHour( new Date() ); // returns 12

在不重新打开网络应用程序的情况下将系统时钟设置为 13:00。

// the referenced bug keeps the same time, but it successfully changes the time zone, so:
var currentDisplayHour = getDisplayHour( new Date() ); // returns 13

在 Mac 和 Windows 7 上的 FF 19.0.0.2 上测试。

注意:由于我无法真正重现 OP 的问题,并且考虑到引用的用例,我什至不确定是否需要任何这些变通方法。人们可能期望对 OP 的用例进行更准确的测试,以同时更改时间和区域。例如,不仅仅是 12:00 -> 13:00,而是 12:00 GMT -> 13:00 BST。更准确的 DST 转换模拟是将时钟设置为 2013-03-31 00:59:00 GMT,检查new Date().getHours(),等待几分钟,然后再次检查小时。

但是,正如我所说,我自己无法重现引用的错误,所以我肯定是错的(在这种情况下,我会修改或删除这个答案)。

无论如何,希望这会有所帮助!

于 2013-03-28T23:47:09.003 回答