文章目录
背景:MySQL中的timestamp和我们平常理解的timestamp有不同,借此背景整理了时间戳相关的知识点
1 时间戳
1.1 unix时间戳(unix timestamp)
定义为从GMT时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
部分操作系统使用32位二进制数字表示时间。此类系统的Unix时间戳最多可以使用到GMT时间2038年01月19日03时14分07秒(二进制:01111111 11111111 11111111 11111111)。其后一秒,二进制数字会变为10000000 00000000 00000000 00000000,发生溢出错误,造成系统将时间误解为1901年12月13日20时45分52秒
使用64位二进制数字表示时间的系统则不会遇到这类溢出问题
不同编程语言的不同精度unix时间戳:(可以使用内置函数设置不同的精度)
- java的时间默认精度是ms,因此unix时间戳是13位
- c++,php默认精度是s,因此unix时间戳是10位
- python默认精度是us,因此unix时间戳是16位
1.2 MySQL时间戳(timestamp)
可以插入两种形式的时间戳,本质上都是“年月日时分秒”字符串
mysql> create table machine.test2(id int,create_time timestamp);
mysql> insert into machine.test2 values(1,'20211110000000');
mysql> insert into machine.test2 values(2,'2021-11-10 00:00:00');
mysql> select * from machine.test2;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 2021-11-10 00:00:00 |
| 2 | 2021-11-10 00:00:00 |
+------+---------------------+
输出的格式为“2021-11-10 00:00:00”
2 MySQL中timestamp和datetime的不同点
timestamp | datetime | |
---|---|---|
输入输出 | 把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储。查询时,将其转化为客户端当前时区进行返回 | 不做任何改变,基本上是原样输入和输出 |
存储 | 4字节 | 8字节 |
MySQL官方文档——时间范围 | ‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’ | ‘1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’ |
验证改变时区对timestamp和datetime的影响
检查当前mysql服务器的时区。其中,CST是中国标准时间(China Standard Time)的缩写,指的是MySQL服务器所在的时区,也就是 UTC+8:00
经过简单测试发现:timestamp类型的字段修改时区后会改变输出时间;datetime则不会
- timestamp
mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | SYSTEM |
+------------------+--------+
mysql> create table machine.test3(id int,create_time timestamp);
mysql> insert into machine.test3 values(1,'20211110000000');
mysql> select * from machine.test3;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 2021-11-10 00:00:00 |
+------+---------------------+
mysql> set time_zone='+0:00';
mysql> select * from machine.test3;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 2021-11-09 16:00:00 |
+------+---------------------+
- datetime
mysql> create table machine.test4(id int,create_time datetime);
mysql> insert into machine.test4 values(1,'20211110000000');
mysql> select * from machine.test4;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 2021-11-10 00:00:00 |
+------+---------------------+
mysql> set time_zone='+0:00';
mysql> select * from machine.test4;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 2021-11-10 00:00:00 |
+------+---------------------+
3 MySQL中关于时间类型的取值范围
官方文档关于时间类型的取值范围说明:
https://dev.mysql.com/doc/refman/8.0/en/datetime.html
3.1 检查MySQL中datetime的时间取值范围
官方文档上的时间范围是'1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999'
,
但是实际可取到的范围是'0000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999
’,
不可取'0000-00-00 00:00:00'
mysql> create table machine.test(id int,recover_time datetime);
mysql> insert into machine.test values(1, '1000-01-01 00:00:00');
mysql> insert into machine.test values(2, '0000-01-01 00:00:00');
mysql> insert into machine.test values(3, '0999-01-01 00:00:00');
mysql> insert into machine.test values(4, '9999-12-31 23:59:59');
mysql> select * from machine.test;
+------+---------------------+
| id | recover_time |
+------+---------------------+
| 1 | 1000-01-01 00:00:00 |
| 2 | 0000-01-01 00:00:00 |
| 3 | 0999-01-01 00:00:00 |
| 4 | 9999-12-31 23:59:59 |
+------+---------------------+
mysql> insert into machine.test values(5, '0000-00-00 00:00:00');
ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'recover_time' at row 1
3.2 检查MySQL中timestamp的时间取值范围
官方文档上的时间范围是'1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999'
但因为我们所在的时区是CST东八区,因此起始时间都比官方文档上的要早8个小时,
也就是'1970-01-01 08:00:01.000000' 到 '2038-01-19 11:14:07.999999'
不可取临界值'1970-01-01 08:00:00'
和'2038-01-19 11:14:08'
mysql> create table machine.test1(id int,create_time timestamp);
mysql> insert into machine.test1 values(1, '1970-01-01 08:00:01');
mysql> insert into machine.test1 values(2, '2038-01-19 11:14:07');
mysql> select * from machine.test1;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 1970-01-01 08:00:01 |
| 2 | 2038-01-19 11:14:07 |
+------+---------------------+
mysql> insert into machine.test1 values(3, '1970-01-01 08:00:00');
ERROR 1292 (22007): Incorrect datetime value: '1970-01-01 08:00:00' for column 'create_time' at row 1
mysql> insert into machine.test1 values(4, '2038-01-19 11:14:08');
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 11:14:08' for column 'create_time' at row 1
4 NULL值和空串问题
NULL也就是在字段中存储NULL值,空值也就是字段中存储空字符(’’)
4.1 占用空间大小
mysql> select length(NULL), length('');
+--------------+------------+
| length(NULL) | length('') |
+--------------+------------+
| NULL | 0 |
+--------------+------------+
空值(’’)的长度是0,是不占用空间的;而NULL的长度是NULL,它是占用空间的,NULL需要额外空间来记录它们的值是否为NULL
官方文档关于NULL值的说明:
https://dev.mysql.com/doc/refman/8.0/en/static-format.html
4.2 MySQL中的时间类型是否可以插入NULL值/空串
datetime可以插入NULL值,不可以插入空串(’’)
mysql> insert into machine.test values(6, NULL);
mysql> select * from machine.test;
+------+---------------------+
| id | recover_time |
+------+---------------------+
| 1 | 1000-01-01 00:00:00 |
| 2 | 0000-01-01 00:00:00 |
| 3 | 0999-01-01 00:00:00 |
| 4 | 9999-12-31 23:59:59 |
| 6 | NULL |
+------+---------------------+
mysql> insert into machine.test values(7, '');
ERROR 1292 (22007): Incorrect datetime value: '' for column 'recover_time' at row 1
timestamp可以插入NULL值,不可以插入空串(’’)
mysql> insert into machine.test1 values(5, NULL);
mysql> select * from machine.test1;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1 | 1970-01-01 08:00:01 |
| 2 | 2038-01-19 11:14:07 |
| 5 | NULL |
+------+---------------------+
mysql> insert into machine.test1 values(6, '');
ERROR 1292 (22007): Incorrect datetime value: '' for column 'create_time' at row 1
MySQL的配置文件sql_mode中,配置了NO_ZERO_DATE / NO_ZERO_IN_DATE的时候,往datetime/timestamp里写空串会报错。检查当前MySQL的配置
mysql> select @@sql_mode;
+-----------------------------------------------------------------------------------------------------------------------+
| @@sql_mode |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
如果需要插入空串(’’),需要删除NO_ZERO_DATE、NO_ZERO_IN_DATE,并重启MySQL