如何处理服务器和客户端之间的时区?
Posted
技术标签:
【中文标题】如何处理服务器和客户端之间的时区?【英文标题】:How to deal with timezones between server and client? 【发布时间】:2013-08-10 01:46:04 【问题描述】:我正在开发一个网站,我必须在其中处理来自用户的不同可能时区。这成为一个大问题,因为该网站会举办拍卖等耗时的活动。
服务器上的所有日期/时间均采用 UTC。数据库以 UTC 时间戳存储所有内容。 php 默认时区也设置为 UTC (date_default_timezone_set('UTC');
)。
现在,我的问题是我应该如何与用户交互,无论我是只显示一个日期,还是更重要的是,我是从用户输入中读取日期/时间。
一个具体的例子:
拍卖有一个截止日期,我将其作为 UTC 存储在数据库中。 当我在网站上查看拍卖时,javascript 计时器使用Date
对象来计算剩余时间。它会自动将时区转换为 GMT+0100(我的本地时区)。因此,如果截止日期是'2013-08-08 10:46:08'
(UTC),则 javascript 日期对象将返回 Aug 08 2013 11:26:15 GMT+0100 (GMT Standard Time)
。
如果当前时间大于 11:46:08,则计时器表示剩余时间为 00:00(这是正确的)。
但如果我尝试插入出价,服务器会接受,因为mysql INSERT
上的条件评估为true
:
INSERT INTO Bids ... WHERE ... ANDuction_deadline > NOW() ...
(因为auction_deadline = '2013-08-08 10:46:08'
and NOW() = '2013-08-08 10:26:50'
)
所有这些时区的胡言乱语都让我大吃一惊。我在这里想念什么?我几乎可以肯定,在数据库中以 UTC 格式存储所有日期/时间是最好的。我只是想不通如何在用户和数据库之间处理它。
【问题讨论】:
如果你需要一些代码来澄清我的问题,请说出来。 【参考方案1】:您的问题根本不涉及时区,只是客户可以转动他们的时钟或使他们的时钟显着倾斜这一事实。为此,解决方法是每隔一段时间轮询一次服务器,以便在计算中使用偏移修复。
事实上,您甚至不需要日期对象。拍卖结束时有一个特定的通用时刻。假设它是1375960662823
。现在,通用的即时时间是1375960669199
,因此我们看到拍卖会在 6 秒后结束(1375960662823 - 1375960669199 ~ 6000
)。无论我在摩洛哥还是日本,它都会在 6 秒内结束。你明白了吗?
要生成这些数字,您可以在客户端调用var now = Date.now() + skewFix
,其中skewFix
是在客户端出现时间偏差或手动将其计算机设置为错误时间时需要应用的更正。
在 PHP 中,您可以使用 $now = time() * 1000;
生成它
【讨论】:
【参考方案2】:这是一个相当典型的主题,但对大多数人来说却非常复杂。首先,你从来没有提到夏令时。是的,我正在增加你的紧张感:)。
现在让我们看看如何做到这一点。您通过在 UTC 中节省时间做得很好。现在,我希望您已经注册了会员,并且每个会员都可以设置自己喜欢的时区,否则您将向他们显示基于服务器时区的时间。
当您通过“开始时间”向用户发送时,您必须在将 UTC 时间转换为他们的时间后发送它们,同样,当您从浏览器接受 TIME 时,无论是用户操作还是 javascript,您都需要将该时间转换为 UTC,考虑到用户是他为个人资料选择的时区。
希望你能弄清楚你哪里出错了?请仔细阅读夏令时,因为当您继续使用其他逻辑时,夏令时也将发挥重要作用。
编辑:
您可以使用 javascript 的时区偏移量,根据他的设置自动提交和用户输入。
【讨论】:
【参考方案3】:JavaScript 中的日期使用本地时区。您应该获取用户的 UTC 时间并将其发送到服务器
new Date
Thu Aug 08 2013 17:00:14 GMT+0530 (India Standard Time)
(new Date("Thu Aug 08 2013 17:00:14")).toUTCString();
"Thu, 08 Aug 2013 11:30:14 GMT"
这将解决服务器和客户端之间的时区问题。
【讨论】:
【参考方案4】:你说
(因为auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')
在 MySQL 中 - NOW
返回服务器本地时区 (docs) 中的当前时间。
您可能想要UTC_TIMESTAMP
之类的东西,它以UTC 格式返回当前时间(docs)。
另外 - 您可能根本不应该接受来自客户端 JavaScript 的任何输入时间。只相信自己的时钟。出价时,请在 MySQL 或 PHP 中使用您的服务器上的时间。不要接受它作为输入。
【讨论】:
【参考方案5】:您可以执行以下操作
加载页面后,向服务器发送一个带有用户时区偏移量的 ajax 请求。您可以使用以下代码获取时区偏移量。
var curdate = new Date()
var offset = curdate.getTimezoneOffset()
offset 是以分钟为单位的时区偏移量。
我认为这会有所帮助。
【讨论】:
【参考方案6】:每次从客户端获取日期时,都可以使用 getUTC 转换为 UTC 日期,即:
var todayDate = new Date();
var todayDateInUTC = new Date(todayDate.getUTCFullYear(), todayDate.getUTCMonth(), todayDate.getUTCDate(), todayDate.getUTCHours(), todayDate.getUTCMinutes(), todayDate.getUTCSeconds());
因此,在您将投标日期插入数据库之前,请使用 getUTC 函数将其转换为 UTC 格式。
【讨论】:
以上是关于如何处理服务器和客户端之间的时区?的主要内容,如果未能解决你的问题,请参考以下文章