我正在开发一个网站,在那里我必须处理来自用户的不同时区。这就成了一个大问题,因为该网站会举办拍卖等时间敏感的活动。
服务器上的所有日期/时间都以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
:插入投标。。。在哪里。。。AND auction_deadline>NOW()。。。
(因为auction_deadline='2013-08-08 10:46:08'
和NOW()='2013-08-08 10:26:50'
)
所有这些时区的胡言乱语都融化了我的大脑。我在这里错过了什么?我几乎可以肯定,将所有日期/时间以UTC存储在数据库中是最好的。我只是想不清楚如何在用户和数据库之间处理它。
您的问题根本不涉及时区,只涉及客户端可以转动时钟或使时钟大幅偏斜的事实。为此,修复方法是每隔一段时间轮询服务器,以获取要在计算中使用的偏移修复。
事实上,您甚至不需要日期对象。拍卖结束时有一个普遍的时刻。假设它是1375960662823
。现在,通用时刻是1375960669199
,因此我们可以看到拍卖在6秒内结束(1375960662823 - 1375960669199 ~ 6000
)。无论我在摩洛哥还是日本,比赛都将在6秒后结束。你明白了吗?
要生成这些数字,在客户端,您可以调用var now = Date.now() + skewFix
,其中skewFix
是在客户端出现时间偏移或手动将计算机设置为错误时间时需要应用的校正。
在PHP中,您可以使用$now = time() * 1000;
生成它
这是一个典型的主题,但对大多数人来说非常复杂。第一件事,你从来没有提到节约白天。是的,我正在增加你的紧张情绪:)。
现在让我们看看如何做到这一点。您将时间保存为UTC,做得很好。现在,我希望您已经注册了成员,每个成员都可以设置自己喜欢的时区,否则您将向他们显示服务器基于时区的时间。
当你通过"开始时间"给用户时,你必须在将UTC时间转换为他们的时间后发送他们,类似地,当你从浏览器接受time时,无论是用户操作还是javascript,你都需要将该时间转换为UTC,考虑到用户是他为其配置文件选择的时区。
希望这能澄清你哪里出了问题?请通读日光节约,因为当你们继续推进其他逻辑时,这也将发挥重要作用。
编辑:
您可以使用javascript的时区偏移量,根据他的设置进行自动提交和用户输入。
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"
这将解决服务器和客户端之间的时区问题。
你说
(因为auction_deadline="2013-08-08 10:46:08"和NOW()="2013-08 10:26:50")
在MySQL中,NOW
返回服务器本地时区(docs)中的当前时间。
您可能想要类似UTC_TIMESTAMP
的内容,它以UTC(文档)形式返回当前时间。
此外,您可能根本不应该接受来自客户端JavaScript的任何输入时间。只相信你自己的时钟。当出价时,在MySQL或PHP中使用服务器上的时间。不要接受它作为输入。
您可以执行以下
加载页面后,向服务器发送一个ajax请求,请求的时区偏移量为用户。您可以使用以下代码获取时区偏移量。
var curdate = new Date()
var offset = curdate.getTimezoneOffset()
offset是以分钟为单位的时区偏移量。
我认为这会有所帮助。
每次从客户端获取日期时,都可以使用getUTC转换为UTC日期,即:
var todayDate = new Date();
var todayDateInUTC = new Date(todayDate.getUTCFullYear(), todayDate.getUTCMonth(), todayDate.getUTCDate(), todayDate.getUTCHours(), todayDate.getUTCMinutes(), todayDate.getUTCSeconds());
因此,在将投标日期插入数据库之前,请使用getUTC函数将其转换为UTC格式。