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 > 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 < 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()
应用于TIMESTAMP
或DATETIME
列。它的倒数是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 个字节。)
没有任何转换函数,获取TIMESTAMP
和DATETIME
看起来一样:
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 5.7 版本不允许在日期时间字段中插入完整日期*