【问题标题】:How to handle MySQL timezone in script如何在脚本中处理 MySQL 时区
【发布时间】:2015-03-29 08:48:00
【问题描述】:

我正在开发一个移动应用程序。从应用程序调用基于模式 (?mode=xx) 运行不同查询的 Web 服务

在其中一些查询中,我使用日期函数,例如 DATE(NOW())。

存储在 MySQL 数据库中的数据存储在 GMT-7(加拿大山地时间)。

我尚未为此 Web 服务注册域/主机,但当我注册时,可以说它托管在另一个城市,例如多伦多(格林威治标准时间 5 - 提前 2 小时)。然后在加拿大山区时间晚上 10:05,用户使用该应用程序发送一个 Web 请求调用,该调用具有如下查询:

SELECT DATE(NOW()) 

由于服务器托管在多伦多,因此将返回明天的日期,即使用户所在的位置是前一天,并且应用程序根据当天显示数据。

有人对此有什么想法吗?

编辑:

SYSTEM
2015-01-29 16:19:48
2015-01-29 23:19:48

是运行查询的结果 select @@time_zone, now(), utc_timestamp()

查询处理日期 (yyyy-mm-dd) 和时间 (hh:mm:ss) 列类型。

【问题讨论】:

  • How to set time zone of mysql? 的可能重复项
  • 使用timestamp 列数据类型来存储日期值。由于它是 UTC,因此实际时区无关紧要。您所要做的就是获取正在使用您的数据库的用户的时区,以便您可以根据他们的时区格式化时间。
  • @RyanVincent - 你错了,好吧,一切。但是,如果您认为自己是对的,请随时发布答案。另外,我希望你是一个聪明的人,我只想礼貌地让你知道我有 0 意图或愿意进入互联网与你争论所以让我们节省我们的时间并停止交谈在我发帖后互相交流。
  • @andrewb - 正确,您可以将用户的时区传递给 Web 服务,或者在客户端应用程序上使用时间后“询问”设备的时区。我不喜欢移动开发,但在 JavaScript 中,我知道如何在不将该信息传递给服务器的情况下获取使用该网站的人的当前时区。很多事情都是可能的,但重要的是在数据库上节省公共时区和格式的时间。它使时区偏移变得容易。
  • @N.B 很抱歉我的困惑 - 我从 cmets 针对我自己提供的有用 cmets 中学到了很多东西。感谢大家分享您的知识。我很感激。说真的,我错了,学到了很多。

标签: mysql datetime timezone unix-timestamp datetime-conversion


【解决方案1】:

您在 MySQL 服务器上运行了这个时间诊断查询。

select @@time_zone, now(), utc_timestamp()

从您的本地时间和 UTC 时间可以清楚地看出,您的服务器机器的系统时区设置是“加拿大/山区”,而 MySQL 服务器软件没有自己的时区设置。

如果你拿起你的桌子并将它们原封不动地移动到附近某个时区的服务器上,你可以随时更新你的软件来发出命令

set time_zone = 'Canada/Mountain';

从您的软件连接后。这将使您的新 MySQL 连接在时区方面表现得像您当前的连接一样。如果您拥有 MySQL 服务器,则可以根据此页面上的说明设置其默认时区。 http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

现在,这是关于时间数据类型的故事。 DATETIMEDATETIME 都是 timezone-ignorant。存储日期/时间值后,即使您更改时区设置,您也会将其恢复为相同的值。

TIMESTAMP 数据类型时区敏感。这些数据项始终存储在UTC, also known as Z, time,以前称为格林威治标准时间。它们在存储时始终转换为 UTC,并在检索时始终转换回。

用于获取当前日期和时间的builtin functionsNOW() 和朋友)时区敏感。他们将在当地时间产生价值。例外情况是三个以UTC_ 开头的函数,它们产生UTC 时间的值。

许多 MySQL 多时区应用程序使用以下操作规程:

  1. 向每个用户询问用户偏好的时区,或从有关用户的其他一些个人数据中找出。 (电话从网络中提供了这些信息。)代表用户将其存储为zoneinfo-friendly 时区描述符('America/New_York'、'Canada/Mountain'、'Europe/Vienna'等)。
  2. 代表用户建立 MySQL 会话后,使用set time_zone 查询设置用户的时区,如上所示。您应该在connect 操作后立即执行此操作。
  3. 将用户的日期和时间存储到TIMESTAMP 数据类型中。它们会在存储时转换为 UTC。
  4. 根据需要检索它们。它们将被转换回当地时间。

这个想法是您的用户的时区是她的上下文的一部分。这很有效,因为如果用户 A 在温哥华而用户 B 在哈利法克斯,并且由于某种原因用户 B 查看用户 A 的时间数据,它将或多或少地自动以大西洋时间显示给 B。

这也很好,因为它可以透明地处理全球变幻莫测的日光到标准时间的变化。去年夏天的时间戳将显示为去年夏天的当地时间。

许多供全球使用的服务器管理员将其系统服务器时间或 MySQL 默认时区设置为 UTC。 (你的没有。)

处理这一切的另一种方法是您开始的方式。选择一个时区并存储与该时区相关的时间戳。在这种情况下,最好选择一个不会在白天和标准时间之间交替的时区。然后,在将时间存储到数据库中时,进行显式转换。您可以通过执行此类操作来存储渥太华用户的时间。

INSERT INTO tbl (appt) VALUES ( 'whatever-time' - INTERVAL 120 MINUTE)

你会以同样的方式得到值。这很容易出错,但你可以让它工作。

最后,您可以自己进行转换。 如果您想知道某个任意时区和 UTC 之间有多少分钟的偏移量,请尝试这两个查询。

set time_zone = 'Canada/Atlantic';
select timestampdiff(minute, utc_timestamp(), now());

每年的这个时候回馈 -240,即 -4:00。由于在某些国家/地区存在半小时或一刻钟时区偏移,您需要使用分钟而不是小时。

最后,小心。 TIMESTAMP 数据类型不代表 1970 年之前的时间。而且,在我的 MariaDB 10.0 实例上,当时间超过 32 位时,它似乎在 2038-01-19T03:14:07 UTC 之后立即陷入困境.

【讨论】:

  • 我在一个医疗保健系统上工作,该系统以东部标准时间存储所有内容。美国医疗保险有一个叫做“午夜三点规则”的东西,它决定了他们是否会支付住院康复费用。在 10 月底,我们非常接近错误地计算了亚利桑那州患者的这条规则(它不会从白天来回切换到标准)。这一次的东西,用新英格兰的行话来说,很难说对。如果你可以让其他人为你做时区,那就去做吧!
猜你喜欢
  • 2014-06-02
  • 2011-06-27
  • 2016-10-17
  • 2014-06-13
  • 2013-07-30
  • 1970-01-01
  • 2011-06-15
  • 2015-08-31
  • 1970-01-01
相关资源
最近更新 更多