MySQL的时间戳2038年问题还有16年,最好在设计上的时候使用datetime就可以了,不要使用时间戳字段了,即使用了也不要用int类型进行映射,使用long类型映射即可

Posted freewebsys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL的时间戳2038年问题还有16年,最好在设计上的时候使用datetime就可以了,不要使用时间戳字段了,即使用了也不要用int类型进行映射,使用long类型映射即可相关的知识,希望对你有一定的参考价值。

目录

前言


本文的原文连接是:
https://blog.csdn.net/freewebsys/article/details/127455169

未经博主允许不得转载。
博主CSDN地址是:https://blog.csdn.net/freewebsys
博主掘金地址是:https://juejin.cn/user/585379920479288
博主知乎地址是:https://www.zhihu.com/people/freewebsystem

1,关于mysql时间戳的2038年BUG


在linux 设计上,使用了int代表时间,当时设计的还不错。

当 timestamp 存储的时间大于 ‘2038-01-19 03:14:07’ UTC,mysql就会报错,
因为这是 mysql自身的问题,也就是说 timestamp是有上限的,超过了,自然会报错。

  1. timestamp的时间范围是:‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC ,自动时区转化,实际存储毫秒数,4字节存储
  2. datetime的时间范围:‘1000-01-01 00:00:00’ to ‘9999-12-31 23:59:59’ ,不支持时区,8字节存储

但是真的到了2038年会咋样呢?

2,使用Docker创建MySQL 模拟下


在默认的Linux 系统上开启了时间同步需要停止下,然后直接设置成2038年2月1日。
创建表之后在修改时间,在linux 系统上进行修改。
不是进入docker 环境中修改。

sudo systemctl stop systemd-timesyncd

sudo date -s 20380202
[sudo] test 的密码: 
2038年 02月 02日 星期二 00:00:00 CST

这里需要使用最新的myslq 版本。因为5.7 好像日期变了直接异常了:
起码DBA是要在这之前升级到新版本,忙活了。

2038-02-01T16:00:14.626767Z 6 [Warning] Iteration 1: Current time obtained from system is greater than 2038
2038-02-01T16:00:14.626778Z 6 [Warning] Iteration 2: Current time obtained from system is greater than 2038
2038-02-01T16:00:14.626786Z 6 [Warning] Iteration 3: Current time obtained from system is greater than 2038
2038-02-01T16:00:14.626794Z 6 [Warning] Iteration 4: Current time obtained from system is greater than 2038
2038-02-01T16:00:14.626801Z 6 [Warning] Iteration 5: Current time obtained from system is greater than 2038
2038-02-01T16:00:14.626809Z 6 [ERROR] This MySQL server doesn't support dates later than 2038
2038-02-01T16:00:14.627757Z 0 [Note] Giving 2 client threads a chance to die gracefully
2038-02-01T16:00:14.627821Z 0 [Note] Shutting down slave threads
2038-02-01T16:00:16.627925Z 0 [Note] Forcefully disconnecting 2 remaining clients

启动最新的mysql 8 :

docker run -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -v /data/mysql:/var/lib/mysql --name mysql mysql:debian

# 设置密码root 
# 设置存储文件在/data/mysql 目录才可以启动成功。

创建数据库和表:


CREATE DATABASE demo DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 


CREATE TABLE `test_time` (
  `id` bigint(16) NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
  `time1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试时间表';

然后插入下,确实插入有问题了。

mysql>   insert into sys_test(id,time1) values (1, now());
ERROR 1292 (22007): Incorrect datetime value: '2038-02-01 16:00:45' for column 'time1' at row 1
mysql> 

但是进行查询的时候:

mysql> SELECT FROM_UNIXTIME ( UNIX_TIMESTAMP() )
    -> ;
+------------------------------------+
| FROM_UNIXTIME ( UNIX_TIMESTAMP() ) |
+------------------------------------+
| 2038-02-01 16:05:20                |
+------------------------------------+
1 row in set (0.00 sec)

mysql> select UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
|       2148653589 |
+------------------+
1 row in set (0.00 sec)

mysql> SELECT FROM_UNIXTIME ( 2147483647 )
    -> ;
+------------------------------+
| FROM_UNIXTIME ( 2147483647 ) |
+------------------------------+
| 2038-01-19 03:14:07          |
+------------------------------+
1 row in set (0.00 sec)

模拟的方式,首先使用最新的mysql 8 ,然后创建库和表,再插入数据。
重启 mysql 8 ,首先只有mysql 8 最新的是可以启动成功。其他的版本没有实验。

然而并没有出现查询出 1970 年的情况,没有溢出,说明数据库已经对时间戳进行升级,支持 2147483647 以上的数据了。

但是要是对数据库进行映射 还是需要使用 long 型比较稳妥。
或者数据库直接换成 datetime 类型即可。

3,总结


所以在设计 mysql 数据表的时候还是要使用 datetime 比较好。
不要使用时间戳字段,虽然还有16年,以后用啥数据库都不知道了。
但是保险起见还是一次到位好,再有datetime 更直观,时间戳看的费劲。
还需要转换,太麻烦了。

本文的原文连接是:
https://blog.csdn.net/freewebsys/article/details/127455169

以上是关于MySQL的时间戳2038年问题还有16年,最好在设计上的时候使用datetime就可以了,不要使用时间戳字段了,即使用了也不要用int类型进行映射,使用long类型映射即可的主要内容,如果未能解决你的问题,请参考以下文章

不用到 2038 年,MySQL 的 TIMESTAMP 就能把我们系统搞崩

PHP & mySQL:2038 年错误:它是啥?如何解决?

2038 ,程序员史上最大危机!

64位MySQL的PHP​​ 2038年问题无法通过PHPMyAdmin插入日期

Java 获取 Unix时间戳

手机日期只能设置到2038年?这背后有个大问题……