如何在脚本中处理MySQL时区

时间:2015-01-29 23:04:59

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

我正在开发一个移动应用程序。从应用程序调用基于模式(?mode = xx)

运行不同查询的Web服务

在其中一些查询中,我使用日期函数,如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,now(),utc_timestamp()

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

1 个答案:

答案 0 :(得分:3)

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

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

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

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

set time_zone = 'Canada/Mountain';
从您的软件连接后立即

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

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

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

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

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

  1. 询问每个用户的用户偏好时区,或者从用户的其他一些个人数据中找出它。 (电话通过网络将这些信息提供给他们。)代表用户存储zoneinfo-friendly时区描述符('America / New_York','Canada / Mountain','Europe / Vienna'等)
  2. 代表用户建立MySQL会话后,使用set time_zone查询设置用户的时区,如上所示。您应该在connect操作后立即执行此操作。
  3. 将用户的日期和时间存储到TIMESTAMP数据类型中。它们将在存储时转换为UTC。
  4. 根据需要检索它们。他们将被转换回当地时间。
  5. 这个想法是你的用户的时区是她的上下文的一部分。这很有效,因为如果用户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实例上,它似乎在2038-01-19T03:14:07 UTC之后立即进入地狱,当时间超过32位。