MySQL时间类型和模式

栏目: 数据库 · 发布时间: 6年前

内容简介:当我在我们可以发现错误信息提示是时间值错误,但是我们这明显是一个合法的时间点啊。经过查询资料,发现原因是在

当我在 MySQL 数据库中尝试插入一条带有时间戳的数据时报错:

mysql> insert into alarm_service values (6, '1970-01-01 08:00:00'); 
ERROR 1292 (22007): Incorrect datetime value: '1970-01-01 08:00:00' for column 'time' at row 1

# 查看表结构
mysql> show create table alarm_service;
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table         | Create Table                                                                                                                                                                                                                         |
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| alarm_service | CREATE TABLE `alarm_service` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 |
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

我们可以发现错误信息提示是时间值错误,但是我们这明显是一个合法的时间点啊。

经过查询资料,发现原因是在 MySQL 中, timestamp 类型的合法区间是 1970-01-01 00:00:01 - 2038-01-19 03:14:07 UTC ,而在存储是,会先将你插入的数据转换为 UTC 时间,然后存储起来,读取的时候,再转换为你的本地时间。由于我的时区为东八区,因此转换后就变为了 1970-01-01 00:00:00 UTC ,成为了非法时间。

解决方案为:

MySQL

下面我们详细说明相关的内容。

MySQL 时间类型

MySQL 时间类型分为三种:

  • DATE: 用于只包含日期不包含时间的时候, MySQL 会将格式转换为 YYYY-MM-DD ,合法范围为 1000-01-01 - 9999-12-31
  • DATETIME: 用于包含日期 + 时间的时候,格式为 YYYY-MM-DD HH:MM:SS ,合法范围为 1000-01-01 00:00:00 - 9999-12-31 23:59:59
  • TIMESTAMP: 用于包含日期 + 时间的时候,格式为 YYYY-MM-DD HH:MM:SS ,合法范围为 1997-01-01 00:00:01 - 2038-01-19 03:14:07 UTC

同时, DATETIMETIMESTAMP 还都支持一个 6 位微秒的数据支持,格式为 YYYY-MM-DD HH:MM:SS[.fraction] ,合法范围为 .000000 - .999999

DATETIMETIMESTAMP 还都提供自动初始化并更新为当前日期和时间的数据。

对于 TIMESTAMP 类型, MySQL 会在存储时将数据值转换为 UTC 标准时间来存储,读取时再转为当前时间。如果你的时区没有发生改变,则该值就是你存储的值,如果你改变了时区,读取到的值就会发生变化。这个特性不会对 DATETIME 生效。

查看时区

mysql> show variables like '%zone%';                                       
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+

可以看到当前设置的时区是 SYSTEM ,即跟操作系统保持一致,同时系统的时区是 CST(China Standard Time 北京标准时间) ,查看系统时间也可以看到是 东8区(+0800)

$ date -R
Tue, 23 Apr 2019 11:22:47 +0800

因此我们输入 1970-01-01 08:00:00MySQL 会纠正为 1970-01-01 00:00:00 ,而成为一个非法值。

非法时间值

对于非法的时间值,针对不同的时间类型, MySQL 会将其转为合适的值: 0000-00-00 或 0000-00-00 00:00:00

比如月份为 1-12 月,当你尝试插入 2019-13-01 00:00:00 时,就会被纠正为 0000-00-00 00:00:00 ,因为不存在 13 月,为非法值。

严格模式

当我们插入非法时间值时,虽然会被纠正,但是在严格模式下,不会插入数据,反而会报错:

ERROR 1292 (22007): Incorrect datetime value: '1970-01-01 08:00:00' for column 'time' at row 1

我们可以通过设置模式,来调整 MySQL 的行为,首先查看 MySQL 的模式:

mysql> show variables like '%sql_mode%';            
+----------------------------+--------------------------------------------+
| Variable_name              | Value                                      |
+----------------------------+--------------------------------------------+                               |
| sql_mode                   | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+----------------------------+--------------------------------------------+

在这个模式下,非法时间会直接报错,我们可以调整模式为 ALLOW_INVALID_DATES

mysql> set session sql_mode = 'ALLOW_INVALID_DATES';
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%sql_mode%';            
+---------------+---------------------+
| Variable_name | Value               |
+---------------+---------------------+
| sql_mode      | ALLOW_INVALID_DATES |
+---------------+---------------------+
1 row in set (0.00 sec)

在这个模式下,不会再完备检查日期的合法性,只会检查月份的范围在 1-12 ,日期在 1-31 。这在处理用户输入的时候很合适,但是这个模式只对于 DATEDATETIME 很合适,对于 TIMESTAMP ,依然需要一个合法的值,否则就会纠正为 0000-00-00 00:00:00

在非法值时,如果这个模式启用,就会报错;如果禁用,就会纠正为 0000-00-00 00:00:00 并产生一个警告:

mysql> insert into alarm_service values (7, '1970-01-01 08:00:00'); 
Query OK, 1 row affected, 1 warning (0.00 sec)

总结

对于这种问题,有两种解决方法:

MySQL

参考资料

  1. 11.3.1 The DATE, DATETIME, and TIMESTAMP Types: https://dev.mysql.com/doc/ref...
  2. 5.1.13 MySQL Server Time Zone Support: https://dev.mysql.com/doc/ref...
  3. 5.1.11 Server SQL Modes: https://dev.mysql.com/doc/ref...

以上所述就是小编给大家介绍的《MySQL时间类型和模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

引爆点

引爆点

[美] 马尔科姆·格拉德威尔 / 钱清、覃爱冬 / 中信出版社 / 2009-8 / 27.00元

我们的世界看上去很坚固,但在《纽约客》怪才格拉德威尔的眼里,只要你找到那个点,轻轻一触,这个世界就会动起来:一位满意而归的顾客能让新开张的餐馆座无虚席,一位涂鸦爱好者能在地铁掀起犯罪浪潮,一位精明小伙传递的信息拉开了美国独立战争的序幕——这个看起来不起眼的点,却是任何人都不能忽视的引爆点。 《引爆点》是一本谈论怎样让产品发起流行潮的专门性著作。书中将产品爆发流行的现象归因为三种模式:个别人物......一起来看看 《引爆点》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具