【问题标题】:Javascript timer/counter timezone issueJavascript计时器/计数器时区问题
【发布时间】:2013-05-30 01:31:37
【问题描述】:

过去几天我一直在努力解决这个问题,但只是因为它而失去了头发。

我正在使用下面的javascript 作为计时器,它使用时间戳作为开始日期进行计数。我正在使用数据库中的时间戳,该时间戳在计时器启动时保存,因为该时间戳是相对于用户的时区保存的,该时区是在他们的个人资料中选择的。

我的服务器 php 时区设置为“America/Los_Angeles”。我的用户个人资料时区也设置为此。这也是保存时区的格式。

但是,当我运行计时器时,即使我的 php 根据保存的时区显示正确的保存时间,即。 '05/29/2013 6:05:49',计时器从一开始就有额外的时间。所以它看起来像“0 天 12 小时 0 分钟 13 秒”而不是“0 天 0 小时 0 分钟 13 秒”。

这一定是由于 javascript 时区?因为如果我将 TZ 设置为“America/New_York”,例如,它将是“0 天 9 小时 0 分钟 13 秒”,对吗?

我该如何解决这个问题?

JS

<script type="text/javascript">
function DaysHMSCounter(initDate, id){
    this.counterDate = new Date(initDate);
    this.container = document.getElementById(id);
    this.update();
}

DaysHMSCounter.prototype.calculateUnit=function(secDiff, unitSeconds){
    var tmp = Math.abs((tmp = secDiff/unitSeconds)) < 1? 0 : tmp;
    return Math.abs(tmp < 0 ? Math.ceil(tmp) : Math.floor(tmp));
}

DaysHMSCounter.prototype.calculate=function(){
    var secDiff = Math.abs(Math.round(((new Date()) - this.counterDate)/1000));
    this.days = this.calculateUnit(secDiff,86400);
    this.hours = this.calculateUnit((secDiff-(this.days*86400)),3600);
    this.mins = this.calculateUnit((secDiff-(this.days*86400)-(this.hours*3600)),60);
    this.secs = this.calculateUnit((secDiff-(this.days*86400)-(this.hours*3600)-(this.mins*60)),1);
}

DaysHMSCounter.prototype.update=function(){ 
    this.calculate();
    this.container.innerHTML =
    " <strong>" + this.days + "</strong> " + (this.days == 1? "day" : "days") +
    " <strong>" + this.hours + "</strong> " + (this.hours == 1? "hour" : "hours") +
    " <strong>" + this.mins + "</strong> " + (this.mins == 1? "min" : "mins") +
    " <strong>" + this.secs + "</strong> " + (this.secs == 1? "sec" : "secs");
    var self = this;
    setTimeout(function(){self.update();}, (1000));
}

window.onload=function(){ new DaysHMSCounter('05/29/2013 6:05:49', 'timer'); }

</script>

HTML

<div id="timer"></div>

【问题讨论】:

    标签: javascript timer timezone offset


    【解决方案1】:

    首先,您需要考虑您是否有兴趣从特定时刻开始计时。由于以下原因,您不能使用像 05/29/2013 6:05:49 这样的本地日历日期时间来表示:

    • 用户可能在不同的时区
    • 用户可以使用不同的日期格式(MM/DD/YYYYDD/MM/YYYY
    • 由于夏令时转换,时间可能不明确

    因此,您应该将 UTC 值传递给您的用户。浏览器会自动调整用户的本地时区。

    您可以将该值表示为 UTC 1970 年 1 月 1 日之后的整数毫秒数,也可以采用标准化格式(例如 ISO8601,例如 2013-05-29T13:05:49Z2013-05-29T06:05:49-07:00)表示。 PHP 确实具有生成任何这些表示的工具。例如,您可以使用gmdate。示例见this answer

    如果您选择使用 ISO8601 格式,您应该知道它是 JavaScript 的后期添加,并非所有浏览器都原生支持。大多数较新的浏览器都支持它,但如果您想要最好的兼容性,您将需要使用诸如 moment.js 之类的库(它还提供许多其他强大的功能)。

    如果您使用整数值,则不需要库,可以直接将其传递给Date 构造函数,但您可能会发现调试起来更加困难。

    另外,出于mentioned in this post 的原因,您可能希望将服务器时区设置为UTC 而不是America/Los_Angeles

    【讨论】:

    • 我通过 htaccess 将我的服务器设置为 UTC,然后根据时区在前端转换和表示所有数据。计时器现在似乎工作了!谢谢你的建议。
    【解决方案2】:

    您的问题是您在没有时区的情况下以文本格式传递日期。因此,日期是在您当地的时区中创建的。

    如果您改为让服务器发送过去纪元的毫秒数(而不是字符串格式的日期),那么您可以使用new Date( millisPastEpoch ),一切都应该很好。

    或者,如果您保证知道用户的时区,那么您可以发送格式为用户时区而不是服务器时区的日期。

    【讨论】:

    • 会和unix时间戳一样吗?这就是它保存到数据库的方式。
    • 许多系统将时间戳存储为一个纪元之后的毫秒数(甚至 javascript 在内部也是如此)。许多(如果不是全部)符合使用“00:00:00 January 1, 1970, UTC”作为纪元。然而,一些数据库在内部将DATETIME 存储为字符串。但是如果你已经将它保存为纪元,那么是的,发送它。
    • @dragonfeet2012 “Unix 时间戳”通常指的是 。您需要 毫秒。如果你愿意,你可以乘以 1000。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 2011-02-16
    相关资源
    最近更新 更多