我正在开发一个移动应用程序。从应用程序调用 Web 服务,该服务根据模式运行不同的查询 (?mode=xx)
在其中一些查询中,我使用日期函数,如DATE(NOW())。
存储在MySQL数据库中的数据存储在GMT-7(加拿大山区时间)中。
我还没有为此网络服务注册域/主机,但是当我注册时,假设它托管在不同的城市,例如多伦多(GMT-5 - 提前2小时)。然后在加拿大山区时间晚上 10:05,用户使用该应用程序发送具有如下查询的 Web 请求调用:
SELECT DATE(NOW())
由于服务器托管在多伦多,因此将返回明天的日期,即使用户所在的位置是前一天,并且应用程序根据当天显示数据。
有人对此有任何想法吗?
编辑:
SYSTEM
2015-01-29 16:19:48
2015-01-29 23:19:48
是运行查询选择的结果 @@time_zone, 现在(), utc_timestamp()
查询处理日期 (yyyy-mm-dd) 和时间 (hh:mm:ss) 列类型。
您在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
、TIME
和DATETIME
都与时区无关。存储日期/时间值后,即使您更改时区设置,也会将其恢复为相同的值。
TIMESTAMP
数据类型对时区敏感。 这些数据项始终以 UTC(也称为 Z 时间)存储,以前称为格林威治标准时间。它们在存储时始终转换为 UTC,并在检索时始终转换回。
用于获取当前日期和时间(NOW()
和朋友)的内置函数对时区敏感。 它们将在本地时间生成值。例外情况是以 UTC_
开头的三个函数,它们以 UTC 时间生成值。
许多MySQL多时区应用程序使用以下操作规则:
- 向每个用户询问用户偏好时区,或者从有关用户的其他一些个人数据中找出它。(电话从网络向电话提供此信息。代表用户将其存储为区域信息友好的时区描述符("美国/New_York"、"加拿大/山地"、"欧洲/维也纳"等)。
- 代表用户建立MySQL会话后,使用如上所示的
set time_zone
查询设置用户的时区。您应该在connect
手术后立即执行此操作。 - 将用户的日期和时间存储为
TIMESTAMP
数据类型。它们将在存储时转换为 UTC。 - 根据需要检索它们。它们将转换回本地时间。
这个想法是用户的时区是其上下文的一部分。这很有效,因为如果用户 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 之后立即