详解MySQL中timestamp和datetime时区问题导致做DTS遇到的坑


Posted in MySQL onDecember 06, 2021

MySQL中如何表示当前时间?

其实,表达方式还是蛮多的,汇总如下:

 

Data Type “Zero” Value
DATE '0000-00-00'
TIME '00:00:00'
DATETIME '0000-00-00 00:00:00'
TIMESTAMP '0000-00-00 00:00:00'
YEAR 0000

datetime和timestamp这两种类型都是用于表示YYYY-MM-DD HH:MM:SS 这种年月日时分秒格式的数据,但两者还是有些许不同之处的。

结论

  • timestamp实际存储的是1970-01-01 00:00:00 UTC到目前的秒数占4字节(时间精度为毫秒和纳秒时会占用更多字节),故相当于是带时区的时间,通过设置会话的时区,会自动转换为设置的时区的时间
  • datetime存储的就是格式化后的字符串类似'2021-12-05 13:27:53.957033',不携带时区信息,在UTC和CST时区查询到的结果是一致的,例如在CST时区写入的'2021-12-05 13:27:53.957033',但是在UTC时区查询到的还是'2021-12-05 13:27:53.957033',如果没做时区转换,就相当于是直接将CST时间映射为UTC时间,但是实际上UTC时间比CST时间慢8个小时

验证

环境准备,简而言之就是存在一张表有timestamp字段和datetime字段,且当前服务端为CST时区

mysql> show create table test_time\G;
*************************** 1. row ***************************
Table: test_time
Create Table: CREATE TABLE `test_time` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ts` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  `dt` datetime(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)

插入一条数据,当前CST时区下ts和dt结果相同

mysql> select * from test_time;
Empty set (0.00 sec)

mysql> insert into test_time() values();
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_time;
+----+----------------------------+----------------------------+
| id | ts                         | dt                         |
+----+----------------------------+----------------------------+
|  3 | 2021-12-05 15:04:13.293949 | 2021-12-05 15:04:13.293949 |
+----+----------------------------+----------------------------+
1 row in set (0.00 sec)

将会话的时区设置为UTC时区再次查询,ts由于从CST时区变为UTC时区查询到的结果比之前慢8个小时,由于dt不带时区信息,结果不变

mysql> set time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_time;
+----+----------------------------+----------------------------+
| id | ts                         | dt                         |
+----+----------------------------+----------------------------+
|  3 | 2021-12-05 07:04:13.293949 | 2021-12-05 15:04:13.293949 |
+----+----------------------------+----------------------------+
1 row in set (0.01 sec)

从刚刚insert产生的binlog中也有体现,ts在binlog中存储为时间戳(从1970-01-01 00:00:00 UTC到目前的秒数)相当于带UTC时区信息,dt为不带时区信息,结果为格式化后的字符串2021-12-05 15:04:13.293949,主要关注倒数第4第5行,@2=1638687853.293949表示ts字段的值, @3='2021-12-05 15:04:13.293949'表示dt字段的值

[mysql %] mysqlbinlog -v --base64-output=decode-rows ./mysqlbin.000012
... ...
SET @@SESSION.GTID_NEXT= '1cf4493a-dafd-11eb-944c-4016af29c14c:1416767'/*!*/;
# at 14220
#211205 15:04:13 server id 1  end_log_pos 14308 CRC32 0x1fd913a3 Query thread_id=137 exec_time=0 error_code=0
SET TIMESTAMP=1638687853.293949/*!*/;
BEGIN
/*!*/;
# at 14308
#211205 15:04:13 server id 1  end_log_pos 14368 CRC32 0xbb8937fb Table_map: `testa`.`test_time` mapped to number 121
# at 14368
#211205 15:04:13 server id 1  end_log_pos 14423 CRC32 0x2e0a3baa Write_rows: table id 121 flags: STMT_END_F
### INSERT INTO `testa`.`test_time`
### SET
###   @1=3
###   @2=1638687853.293949
###   @3='2021-12-05 15:04:13.293949'
# at 14423
#211205 15:04:13 server id 1  end_log_pos 14454 CRC32 0x68cee280 Xid = 1416
COMMIT/*!*/;

  • 如果在做DTS相关项目时,使用解析MySQL binlog的开源工具,例如github.com/go-mysql-org/go-mysql,如果配置了parseTime=true会将timestamp类型字段解析为Local时间,将datetime类型解析为UTC时间,也可配置为false获取到的就是字符串(timestamp已转换为会话时区的时间,datetime就是binlog中原生的字符串)自己解析,如果parseTime=true且不是使用的UTC时间插入的datetime字段,理论上拿到的时间已经不正确了,相当于直接将CST的2021-12-05 15:04:13.293949转换为了UTC的2021-12-05 15:04:13.293949,实际上应该转换为UTC的2021-12-05 07:04:13.293949才正确
  • 如果刚好业务需求中有time.Now()获取的Local时间和datetime类型字段比较的场景,需要注意时区问题,或者将时间都去掉时区,转换为格式化后的字符串相比较
  • 由于datetime本身就不带时区信息,除了转换UTC时间,也没有更好的选择,所以很坑!

到此这篇关于详解MySQL中timestamp和datetime时区问题导致做DTS遇到的坑的文章就介绍到这了,更多相关MySQL timestamp和datetime坑内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
详解MySQL 用户权限管理
Apr 20 MySQL
简单了解 MySQL 中相关的锁
May 25 MySQL
Mysql 用户权限管理实现
May 25 MySQL
虚拟机linux端mysql数据库无法远程访问的解决办法
May 26 MySQL
浅谈MySQL 亿级数据分页的优化
Jun 15 MySQL
浅谈mysql增加索引不生效的几种情况
Jun 23 MySQL
解决mysql:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO/YES)
Jun 26 MySQL
SQL实战演练之网上商城数据库商品类别数据操作
Oct 24 MySQL
防止web项目中的SQL注入
Dec 06 MySQL
SQL注入详解及防范方法
Dec 06 MySQL
mysql 索引的数据结构为什么要采用B+树
Apr 26 MySQL
MySQL使用IF语句及用case语句对条件并结果进行判断 
Sep 23 MySQL
mysql中整数数据类型tinyint详解
Dec 06 #MySQL
SQL注入详解及防范方法
Dec 06 #MySQL
防止web项目中的SQL注入
Dec 06 #MySQL
mysql创建存储过程及函数详解
Dec 04 #MySQL
mysql5.6主从搭建以及不同步问题详解
MySQL图形化管理工具Navicat安装步骤
全面盘点MySQL中的那些重要日志文件
You might like
基于PHP对XML的操作详解
2013/06/07 PHP
JQuery 构建客户/服务分离的链接模型中Table中的排序分析
2010/01/22 Javascript
Knockoutjs快速入门(经典)
2012/12/24 Javascript
Jquery插件easyUi表单验证提交(示例代码)
2013/12/30 Javascript
JQuery为页面Dom元素绑定事件及解除绑定方法
2014/04/23 Javascript
jquery实现不包含当前项的选择器实例
2015/06/25 Javascript
JS表格组件神器bootstrap table详解(基础版)
2015/12/08 Javascript
jQuery animate和CSS3相结合实现缓动追逐效果附源码下载
2016/04/18 Javascript
jQuery实现下拉框功能实例代码
2016/05/06 Javascript
AngularJs入门教程之环境搭建+创建应用示例
2016/11/01 Javascript
jquery实现超简单的瀑布流布局【推荐】
2017/03/08 Javascript
简单实现js上传文件功能
2017/08/21 Javascript
Angular中点击li标签实现更改颜色的核心代码
2017/12/08 Javascript
vue-cli系列之vue-cli-service整体架构浅析
2019/01/14 Javascript
[01:37]PWL S2开团时刻DAY1&2——这符有毒
2020/11/20 DOTA
Python使用bs4获取58同城城市分类的方法
2015/07/08 Python
Python的GUI框架PySide的安装配置教程
2016/02/16 Python
python文件与目录操作实例详解
2016/02/22 Python
浅谈python中str字符串和unicode对象字符串的拼接问题
2018/12/04 Python
Python3获取电脑IP、主机名、Mac地址的方法示例
2019/04/11 Python
对pyqt5中QTabWidget的相关操作详解
2019/06/21 Python
树莓派使用USB摄像头和motion实现监控
2019/06/22 Python
python按行读取文件并找出其中指定字符串
2019/08/08 Python
python基于K-means聚类算法的图像分割
2019/10/30 Python
Python实现井字棋小游戏
2020/03/09 Python
python Scrapy爬虫框架的使用
2021/01/21 Python
详解HTML5中rel属性的prefetch预加载功能使用
2016/05/06 HTML / CSS
欧洲最大的美妆零售网站:Feelunique
2017/01/14 全球购物
网络事业创业计划书范文
2014/01/09 职场文书
企业给企业的表扬信
2014/01/13 职场文书
人事经理岗位职责
2014/04/28 职场文书
工会主席事迹材料
2014/06/03 职场文书
教师师德师风个人整改方案
2014/09/18 职场文书
2015年统战工作总结
2015/05/19 职场文书
Python 流媒体播放器的实现(基于VLC)
2021/04/28 Python
Java生成日期时间存入Mysql数据库的实现方法
2022/03/03 Java/Android