【问题标题】:When using NOW() in MySQL can I be certain that the correct UTC value will be stored in a TIMESTAMP column?在 MySQL 中使用 NOW() 时,我可以确定正确的 UTC 值将存储在 TIMESTAMP 列中吗?
【发布时间】:2017-10-02 01:46:39
【问题描述】:

MySQL 有两种专门用于存储日期和时间值的数据类型 - DATETIMETIMESTAMP。两种类型都存储时区信息,并且都有不同的规则。

DATETIME 列将存储插入查询中提供的确切日期和时间值。 (没有时区的转换和启示)

TIMESTAMP 列会将插入时提供的日期和时间值从插入时的连接时区转换为 UTC。在检索时,它将从 UTC 存储的日期和时间值转换为检索连接的时区。 两个连接的时区可以根据这些rules显式或隐式设置。

现在,在我回答我的问题之前,让我们先看看在涉及夏令时时处理日期和时间的一些细微差别。总结另一个Stack Overflow question 的答案以及我从MySQL documentation 关于日期/时间的理解:

  1. 当使用DATETIME 列并明确指定一个值(即/2009-11-01 01:30:00)时,该值可能不明确。 DATETIME 不执行任何对话,只是存储这个确切的日期/时间。假设我在纽约(遵循夏令时)。在插入和检索时,我无法指示/知道该值是指有夏令时 (UTC-4) 的凌晨 1:30 还是没有夏令时 (UTC-5) 的凌晨 1:30 )。
  2. 当使用DATETIME 列和NOW() 时,NOW() 计算为查询执行开始时的日期和时间值(即/2009-11-01 01:30:00),并且这个值被插入,没有转换,到DATETIME 字段导致与上面提到的完全相同的歧义。
  3. 当使用TIMESTAMP 列并明确指定一个值(即/2009-11-01 01:30:00)时,我又遇到了与上述相同的问题。无法指定,也无法知道我指的是哪个凌晨 1:30。

现在,这是我的问题:

假设 MySQL 连接设置为包含夏令时的时区(例如 America/New York),我可以确定将 NOW() 插入 TIMESTAMP 列将导致正确的 UTC 日期和时间值存储? UTC 当然不遵守夏令时,因此 1:30am New York timezone with-daylight-savings moment 的 UTC 时间与 1:30AM New York 的 UTC 时间不同没有夏令时的时区

更具体地说:当我从 @987654343 插入/选择时,连接时区的 UTC 偏移量 是在查询执行开始时用于执行 to-UTC/from-UTC 转换的吗@ 柱子?回到我的例子,在凌晨 1:30 有夏令时(America\New York 时区)我在 UTC-4 和凌晨 1:30 没有夏令时(America\New York 时区)我' m 在UTC-5 - 所以在这两个时刻,当我显式插入2009-11-01 01:30:00 或使用NOW() 隐式插入相同的值时,是否会在TIMESTAMP 字段中存储不同的值?最后,如果我在跨越这两个时刻的单个 MySQL 连接中,并且我执行两个查询(第一个时刻一个,第二个时刻一个单独的查询),这两个查询都会导致正确的(不同的)UTC 值要存储吗?

【问题讨论】:

  • 你读过thisthat吗?
  • 数据库 UTC。表示层用户偏好和时区。

标签: mysql date time


【解决方案1】:

您可能希望将它用于服务器:

mysql> SHOW VARIABLES LIKE '%zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | UTC    |  -- Comes from OS
| time_zone        | SYSTEM |  -- Probably the 'right' setting
+------------------+--------+

使用这些设置,SELECT NOW() 将提供 UTC 时间,而不是本地时间。

对于您的个人计算机,最好让system_time_zone 等于Pacific Daylight Time(或其他),以反映您当前的位置。

INSERTingSELECTing 变为DATEDATETIME 时,

不会发生转换。把它想象成时钟的图片。

对于TIMESTAMP,无论你给它什么都转换为/从UTC转换。也就是说,表中存储的位是UTC,但你看不到;您只能看到基于上述两种设置转换后的日期和时间。

我建议获得答案的最佳方法是创建一个带有DATETIMETIMESTAMP 的表,设置这两个设置,然后看看存储时会发生什么。然后更改设置并执行SELECT

【讨论】:

  • 感谢您的回答,但我特别想了解基于位置的时区(例如 America\New York)如何存储在 TIMESTAMP 字段中,以了解该位置何时处于夏令时而不是在夏令时。
  • TIMESTAMP 字段中的位是 UTC。也就是说,在宇宙中的任何给定秒内,任何存储到 ts 字段中的内容都将根据时间和对INSERTer 有效的区域设置进行转换。当SELECTing 时,它会被选择器重新转换。如果它是具有相同设置的同一台计算机,则您将获得所存储的内容。同时,不同区域/DST/etc 中的某人会看到不同的值。
  • 也许您需要制作一个示例,显示一些时间和区域,以及执行的插入操作,以及所需的选择结果。
  • "如果它是同一台计算机,具有相同的设置,您将得到您所存储的内容。"我不确定这是不是真的。我可以在同一个时区,并根据我是在夏令时还是没有夏令时有两个不同的 UTC 偏移量。这就是我的意思。例如,在夏令时,我可能在 UTC-4,而在没有夏令时,我可能在 UTC-5。我的问题不是如何构建一个避免这个问题的数据库方案——我想了解它是如何工作的。
  • 转换基于相关时间的 DST 设置,而不是当前时间
【解决方案2】:

您可以使用SET time_zone 函数测试时区更改:

mysql> create table demo (test timestamp);
mysql> SET time_zone='-06:00';
mysql> insert into demo VALUES(NOW());
mysql> SELECT * FROM demo;
+---------------------+
| test                |
+---------------------+
| 2017-05-23 08:55:16 |
+---------------------+

mysql> SET time_zone='+02:00';
mysql> insert into demo VALUES(NOW());
mysql> SELECT * FROM demo;
+---------------------+
| test                |
+---------------------+
| 2017-05-23 16:55:16 |
| 2017-05-23 16:55:32 |
+---------------------+

根据这些结果,更改时区给出了一致的结果,证明时间是 UTC 存储的(使用 timestamp 时)。

【讨论】:

  • 技术不错。现在也试试(test DATETIME)
  • @RickJames 使用DATETIME,您在最后一次选择时会有 8 小时的差异,这证明使用 DATETIME 时不会存储 UTC 时间。
  • 更改时区是否会更改“8”?
  • @RickJames 从 -03:00 time_zone 切换到 +02:00 会给你 5 小时的时间差,datetime 和 0 的时间戳。最好的办法是自己测试。
【解决方案3】:

据我所知,您最好从您的代码中执行此操作。如果您真的必须通过 DB 进行操作,您可以使用 UTC_TIMESTAMP(),它将始终根据 UTC 为您提供当前时间。然而,在我看来,依赖您的服务器时区并不是一个好主意,因为随着您的增长/扩展,服务器必然会发生变化。

另一方面,从代码中指定时间对您来说往往比让它到达数据库更重要/更准确。 (想想延迟、延迟插入等等)。

【讨论】:

    猜你喜欢
    • 2016-05-20
    • 2017-05-27
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多