当前位置:   article > 正文

MySQL数据时区问题,及datetime和timestamp类型存储的差异_timestamp类型到timedate时间差

timestamp类型到timedate时间差

问题:

查询不同数据库上表中记录时间差距8小时。

昨天协助其他地区同事解决客户查询到不同数据中心时间差距8小时的问题。原因就是时区不同。

解决方案:

设置服务器的时区都为北京时间,即修改数据库服务器的time_zone值为“+8:00”解决。

这个参数,可以在通过mysqld命令启动数据库的时候加上参数 --default-time-zone=timezone来设置时区,

也可以通过my.cnf配置文件的[mysqld]标签里增加 default-time-zone='timezone'这一行来设置。

如果希望即时生效,也可以通过命令修改全局或者会话级别的time_zone的值:

命令如下:

  1. 修改全局time_zone的值
  2. set global time_zone='+8:00';
  3. 修改当前会话的time_zone
  4. set time_zone='+8:00';

其他:

因为使用的云数据库也有在海外地区的,所以针对我们有些表的字段是timestamp类型的情况和遇到的问题,也一起整理了一下。

测试环境为 Windows MySQL 5.7.22-log。

表结构如下:

  1. CREATE TABLE `ee` (
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,
  3.   `date1` datetime(6) DEFAULT NULL,
  4.   `date2` time(2) DEFAULT NULL,
  5.   `date3` timestamp(3) NULL DEFAULT NULL,
  6.   PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

当前数据库服务器的时区设置为(这是本次测试起始的系统时区情况):

即:system_time_zone参数值为+2:00。

test1:

测试目的:同一个会话的time_zone值变化时,插入记录的时间显示的“不同

当前数据库time_zone参数情况如下;

  1. root@iris>show global variables like'%time_zone%';
  2. +------------------+--------+
  3. | Variable_name    | Value  |
  4. +------------------+--------+
  5. | system_time_zone |        |
  6. | time_zone        | SYSTEM |# 数据库使用时区跟system一致,即当前系统时区,是耶路撒冷(+2:00),等同于set time_zone='+2:00'了。
  7. +------------------+--------+

向表iris.ee中插入数据:

INSERT INTO iris.ee(date1,date2,date3) VALUES(NOW(),NOW(),NOW());

查询表数据:

  1. root@iris>select * from iris.ee;
  2. +----+----------------------------+-------------+-------------------------+
  3. | id | date1                      | date2       | date3                   |
  4. +----+----------------------------+-------------+-------------------------+
  5. |  1 | 2018-12-07 09:55:52.000000 | 09:55:52.00 | 2018-12-07 09:55:52.000 |
  6. +----+----------------------------+-------------+-------------------------+
  7. 1 row in set (0.00 sec)

修改当前会话的时区:

  1. root@iris>set time_zone='+8:00';
  2. Query OK, 0 rows affected (0.00 sec)

再次插入数据,并查看表数据:

  1. root@iris>INSERT INTO iris.ee(date1,date2,date3) VALUES(NOW(),NOW(),NOW());
  2. Query OK, 1 row affected (0.18 sec)
  3. #查看表数据
  4. root@iris>select * from iris.ee;
  5. +----+----------------------------+-------------+-------------------------+
  6. | id | date1                      | date2       | date3                   |
  7. +----+----------------------------+-------------+-------------------------+
  8. |  1 | 2018-12-07 09:55:52.000000 | 09:55:52.00 | 2018-12-07 17:55:52.000 |
  9. |  2 | 2018-12-07 17:57:29.000000 | 17:57:29.00 | 2018-12-07 17:57:29.000 | # 看date1的值:原来时区是耶路撒冷(+2:00),改为“+8:00”后,时间变晚了6个小时,从九点变成17点。(分秒的差距是由于执行间隔时间造成)
  10. +----+----------------------------+-------------+-------------------------+
  11. 2 rows in set (0.00 sec)

注意:这里修改time_zone都是会话变量,同一个会话里进行的。

 

test2:

测试目的:修改会话级别和全局级别变量time_zone的差异;

当前表记录为:

  1. root@iris>select * from iris.ee;
  2. +----+----------------------------+-------------+-------------------------+
  3. | id | date1                      | date2       | date3                   |
  4. +----+----------------------------+-------------+-------------------------+
  5. |  1 | 2018-12-07 09:55:52.000000 | 09:55:52.00 | 2018-12-07 22:55:52.000 |
  6. |  2 | 2018-12-07 17:57:29.000000 | 17:57:29.00 | 2018-12-07 22:57:29.000 |
  7. |  3 | 2018-12-07 23:52:08.000000 | 23:52:08.00 | 2018-12-07 23:52:08.000 |
  8. |  4 | 2018-12-07 18:52:31.000000 | 18:52:31.00 | 2018-12-07 23:52:31.000 |
  9. |  5 | 2018-12-07 19:04:08.000000 | 19:04:08.00 | 2018-12-08 00:04:08.000 |
  10. |  6 | 2018-12-07 19:04:13.000000 | 19:04:13.00 | 2018-12-08 00:04:13.000 |
  11. |  7 | 2018-12-07 19:04:34.000000 | 19:04:34.00 | 2018-12-08 00:04:34.000 |
  12. +----+----------------------------+-------------+-------------------------+
  13. 7 rows in set (0.00 sec)

当使用全局级别变量时:

会话1:

会话2:

❤上面两图显示两个会话当前global time_zone都是“+8:00”。

分别在会话1和会话2中插入记录:

  1. session1:
  2. INSERT INTO iris.ee(id,date1,date2,date3) VALUES(11,NOW(),NOW(),NOW());
  3. session2:
  4. INSERT INTO iris.ee(id,date1,date2,date3) VALUES(22,NOW(),NOW(),NOW());

查询表记录:

会话1:

会话2:

❤上面两图表示当前插入的记录在两个会话中时间显示是(相对)一样的(都是同一个时区、当前实际时间--即,我看到手表上显示的时间。)

 

当使用会话级参数设置时:

会话1:

会话2:

❤上面两图表示,当会话1时区为“+1:00”、会话2时区为“+11:00”,相差10小时。

注意:

(1)插入的记录:

  • datetime类型字段,保存的时间都是当前会话所设置的时区相应时间点(即,好比我两个会话都是修改了计算机的系统时间的时区,然后执行insert。执行命令时看到计算机上显示的时间)。

如下图;

  • 而,timestamp类型字段,id=33 和id=44 的记录,是一样的(即,虽然我设定两个会话所在时区不同,但是我同时(假使是同时执行实际,我切换会话执行,时间也就隔了12秒,看上图)在两个会话里insert了,此时他们换算成我所在的时区的时间都是一样的,都跟我现在看到我手表的时间是一样的。),这也是我要说的第二个注意点,timestamp的时区性

 

(2)时间类型不同导致数据显示结果的不同:

    这里涉及到一个问题,timestamp字段类型有时区性,上一个注意事项提到的。

    datetime类型的字段的记录,记录的都是数据插入的时候当前会话所获取到的time_zone相应的时区的即时时间。就算会话或者说服务器设置的时区改变了了,表里这个字段的值也不会发生变化。

    但是timestamp类型的字段的值会随着服务器时区的变化,自动换算成相应的时间。即在不同时区,查询到同一个条记录此字段的值会不一样。

    可能说的比较绕。 还是不明白,可以再来看第二个例子。

例1:

表的数据没做任何update,在同一个会话里,修改了两次time_zone,看到的表ee里字段date3 (timestamp类型)的值变化了,date1(datetime类型)没变。

  • time_zone='+0:00'
  1. root@iris>set time_zone='+0:00';
  2. Query OK, 0 rows affected (0.00 sec)
  3. root@iris>select * from iris.ee;
  4. +----+----------------------------+-------------+-------------------------+
  5. | id | date1                      | date2       | date3                   |
  6. +----+----------------------------+-------------+-------------------------+
  7. |  1 | 2018-12-07 09:55:52.000000 | 09:55:52.00 | 2018-12-07 09:55:52.000 |
  8. |  2 | 2018-12-07 17:57:29.000000 | 17:57:29.00 | 2018-12-07 09:57:29.000 |
  9. +----+----------------------------+-------------+-------------------------+
  10. 2 rows in set (0.00 sec)
  • time_zone='+13:00' 
  1. root@iris>set time_zone='+13:00';
  2. Query OK, 0 rows affected (0.00 sec)
  3. root@iris>select * from iris.ee;
  4. +----+----------------------------+-------------+-------------------------+
  5. | id | date1                      | date2       | date3                   |
  6. +----+----------------------------+-------------+-------------------------+
  7. |  1 | 2018-12-07 09:55:52.000000 | 09:55:52.00 | 2018-12-07 22:55:52.000 |
  8. |  2 | 2018-12-07 17:57:29.000000 | 17:57:29.00 | 2018-12-07 22:57:29.000 |
  9. +----+----------------------------+-------------+-------------------------+
  10. 2 rows in set (0.00 sec)
  11. root@iris>

总结:上面两次对本会话的time_zone进行修改,得到date1字段的值没变,date3字段的值变了。

所以,表中有需要使用时间类型的字段时候,需要根据业务情况选择合适类型,datetime或者timestamp。

当然,这两个类型的差别并不仅限于其时区性,

datetime取值范围:0000-00-00 00:00:00 ~ 9999-12-31 23:59:59;

timestamp取值范围:1970-01-01 08:00:01!2038-01-19 11:14:07 。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/596729
推荐阅读
相关标签
  

闽ICP备14008679号