2

我正在开发一个移动应用程序。从应用程序调用基于模式 (?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) 列类型。

4

1 回答 1

4

您在 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

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

TIMESTAMP数据类型是timezone -sensitive。这些数据项始终存储在UTC,也称为 Z,时间,以前称为格林威治标准时间。它们在存储时始终转换为 UTC,并在检索时始终转换回。

获取当前日期和时间(和朋友)的内置函数是时区敏感的。他们将在当地时间产生价值。例外情况是三个函数以在 UTC 时间产生值开始。NOW()UTC_

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

  1. 向每个用户询问用户偏好的时区,或者从有关用户的其他一些个人数据中找出。(电话从网络中提供了这些信息。)代表用户将其存储为对zoneinfo 友好的时区描述符(“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 之后立即陷入困境。

于 2015-01-30T00:12:41.013 回答