MySQL 5.7 时间戳字段显示日期时间?

Posted

技术标签:

【中文标题】MySQL 5.7 时间戳字段显示日期时间?【英文标题】:MySQL 5.7 Timestamp field showing Datetime? 【发布时间】:2019-09-23 14:18:17 【问题描述】:

我的数据库中有一个名为time 的列。该列的类型为timestamp,默认值为CURRENT_TIMESTAMP

但经过一些插入后,在phpMyAdmin 中,它会将值显示为日期时间,例如2019-05-05 04:24:45 甚至时区也显示在那里并且可以更改!

我认为 mysql时间戳是 4 个字节(与 8 个字节的日期时间相比)并且不存储时区,并且数据与 INT(10) 相同,例如:1557094115(自 1970 年以来经过的秒数或类似的东西)

谁能解释一下,是bug还是什么?

MySQL 版本 5.7.25

编辑 1(截图):

这是一个TIMESTAMP 列,默认值为CURRENT_TIMESTAMP

如您所见,它显示为DATETIME,我无法将它与 unix_timestamp 的整数值进行比较......我们也可以将 TimeZone 更改为任何值(我认为时间戳不存储时区......)

编辑 2:

如果(基于一个答案)MySQL 在内部将其存储为整数,那么为什么我不能将它与整数进行比较? (以下查询无效)

DELETE FROM `table` WHERE time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL :days DAY))

SQLSTATE[22007]:无效的日期时间格式:1292 不正确的日期时间值:第 1 行的列“时间”的“1555980012”

我也在 Sequel Pro 和 MySQLWorkbench 中尝试过,结果相同

【问题讨论】:

在内部,所有内容都以某种方式存储为数字,甚至是字母;这就是计算机的工作方式。但是,您已告诉数据库以特定方式处理这些值,可以是 DateTime 值,也可以是特定时间点。它在内部的存储方式无关紧要,只要它以您告诉它的人类可读格式输出即可。下面的两个答案相互补充,并描绘了 DateTime 和 Timestamp 数据类型之间差异和相似之处的全貌。 那我猜我得用int(10)来存储实际的时间戳 是的,您可以将其存储为整数,但问题是为什么?将其存储为原生 MySQL 类型为您提供了更多选项,为了显示,您可以通过UNIX_TIMESTAMP() 获取自 UNIX 纪元以来秒数的整数值。 我只需要比较 X 秒是否经过(例如事件发生后 300 秒),这可以在 int 上轻松完成,但在 Datetime 上需要额外的功能!即使现在我了解它们是如何存储的,但我仍然不确定如果有人需要,当有实际的 Datetime 类型可用时,它们为什么会将时间戳显示为 Datetime。 @Dharman - 养成将列放在一边而常量表达式放在另一边的习惯,这样优化器就有机会使用 INDEX: myDT &gt; NOW() - INTERVAL 300 SECOND 【参考方案1】:
    DateTime 不存储时区信息(它只是值),而 MySQL 将 TIMESTAMP 值从当前时区转换为 UTC 进行存储,并从 UTC 转换为当前时区进行检索。您从 PhpMyAdmin 看到的是检索到的值,而不是存储的值。 自 MySQL 5.6.4 以来,DateTime 的存储已从 8 个字节提高到 5 个字节(+ 小数秒存储)Reference

【讨论】:

感谢您提供有用的信息。我不知道 MySQL 5.6.4 上的这些更改...但这仍然没有说明为什么时间戳列显示为 Datetime,如我的屏幕截图所示(我编辑了问题以添加它们) 整数是 mysql 在内部存储时间戳和日期时间的方式,并不意味着 UI 会显示数字。我的第一点已经回答了你的问题。您正在处理的是 phpmyadmin,它只是一个 php 客户端。您为所选值选择了时区,但 mysql 将转换并存储为 UTC 值。 如果它在内部存储为整数,那为什么我不能将它与整数进行比较? (以下查询无效)DELETE FROM table WHERE time &lt; UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 2 DAY)) this'internal' 是 mysql 内部的意思,不是说你可以把它当作整数使用。您可以从 mysql 文档dev.mysql.com/doc/internals/en/… 中阅读此内容 如果要比较整数值,则需要将 unix_timestamp 函数应用于两个操作数。 DELETE FROM table WHERE UNIX_TIMESTAMP(time) 【参考方案2】:

如果您需要查看1557094115,则将函数UNIX_TIMESTAMP() 应用于TIMESTAMPDATETIME 列。它的倒数是FROM_UNIXTIME()

mysql> SELECT UNIX_TIMESTAMP("2019-05-05 04:24:45"), FROM_UNIXTIME(1557055485);
+---------------------------------------+---------------------------+
| UNIX_TIMESTAMP("2019-05-05 04:24:45") | FROM_UNIXTIME(1557055485) |
+---------------------------------------+---------------------------+
|                            1557055485 | 2019-05-05 04:24:45       |
+---------------------------------------+---------------------------+

更多

TIMESTAMP 的内部存储 UTC 1557055485;时区在获取/存储时被添加/删除。

DATETIME 的内部存储(逻辑上,但实际上不是)字符串“2019-05-05 04:24:45”,没有时区提示。 (实际上,它以某种方式被打包成 5 个字节。)

没有任何转换函数,获取TIMESTAMPDATETIME看起来一样:

CREATE TABLE `dtts` (
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `dt` datetime DEFAULT NULL,
  `just_date` date NOT NULL,
  `di` int(11) DEFAULT NULL,
  `ts_int` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
1 row in set (0.00 sec)

mysql> select * from dtts
    -> ;
+---------------------+---------------------+------------+------------+------------+
| ts                  | dt                  | just_date  | di         | ts_int     |
+---------------------+---------------------+------------+------------+------------+
| 2017-06-26 17:52:53 | 2011-06-08 20:45:55 | 2011-06-08 |   20110608 | 1465404577 |
| 2017-06-26 17:52:53 | 2013-03-10 02:35:47 | 2013-03-10 |   20130310 | 1465404577 |

NOW() 添加到两者,然后添加SELECTing

mysql> INSERT INTO dtts (ts, dt) VALUES (NOW(), NOW());
Query OK, 1 row affected, 1 warning (0.00 sec)

| 2019-05-08 14:14:07 | 2019-05-08 14:14:07 | 0000-00-00 |       NULL |       NULL |
+---------------------+---------------------+------------+------------+------------+

【讨论】:

非常有用的信息,但它没有回答为什么 timestamp 列不存储时间戳而是存储日期时间? @J.Doe - 它确实存储了 1970 UTC 的秒数。请参阅我的答案。 @J.Doe - 你看不到被子下面的东西。 DATETIME 存储你喂它的东西。 TIMESTAMP 存储 UTC,转换为/从此类。您可以通过询问您在另一个时区的同事从SELECT 得到什么来“看到”差异。【参考方案3】:

从 MySQL 5.6.4 开始,DATETIME 字段需要 5 字节 + 3 字节小数。 TIMESTAMP 类型需要 4 字节 + 3 字节小数。这些数据类型都不存储时区信息。但是,MySQL 和 phpMyAdmin 都根据数据库服务器的时区显示 TIMESTAMP 字段。您可以使用以下语句检索数据库服务器的时区信息:

SELECT @@global.time_zone, @@session.time_zone;
SELECT EXTRACT(HOUR FROM (TIMEDIFF(NOW(), UTC_TIMESTAMP))) AS `timezone`

如果您希望 phpMyAdmin 显示与数据库服务器不同的时区,您可以在 phpMyAdmin 的 config.inc.php 文件中设置 SessionTimeZone 属性。

【讨论】:

以上是关于MySQL 5.7 时间戳字段显示日期时间?的主要内容,如果未能解决你的问题,请参考以下文章

mysql 中,创建表时如何定义一个日期类型的字段

MySql 5.7 版本不允许在日期时间字段中插入完整日期*

mysql格式化日期

如何处理mysql中的时间戳读取问题

如何在 mysql 5.7 上显示从月份的第一个日期到 MYSQL 5.7 上的月底日期的日期? [复制]

mysql格式化日期