詳解MySQL中timestamp和datetime時區(qū)問題導致做DTS遇到的坑
MySQL中如何表示當前時間?
其實,表達方式還是蠻多的,匯總?cè)缦拢?/p>
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 這種年月日時分秒格式的數(shù)據(jù),但兩者還是有些許不同之處的。
結(jié)論
- timestamp實際存儲的是1970-01-01 00:00:00 UTC到目前的秒數(shù)占4字節(jié)(時間精度為毫秒和納秒時會占用更多字節(jié)),故相當于是帶時區(qū)的時間,通過設(shè)置會話的時區(qū),會自動轉(zhuǎn)換為設(shè)置的時區(qū)的時間
- datetime存儲的就是格式化后的字符串類似'2021-12-05 13:27:53.957033',不攜帶時區(qū)信息,在UTC和CST時區(qū)查詢到的結(jié)果是一致的,例如在CST時區(qū)寫入的'2021-12-05 13:27:53.957033',但是在UTC時區(qū)查詢到的還是'2021-12-05 13:27:53.957033',如果沒做時區(qū)轉(zhuǎn)換,就相當于是直接將CST時間映射為UTC時間,但是實際上UTC時間比CST時間慢8個小時
驗證
環(huán)境準備,簡而言之就是存在一張表有timestamp字段和datetime字段,且當前服務(wù)端為CST時區(qū)
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)
插入一條數(shù)據(jù),當前CST時區(qū)下ts和dt結(jié)果相同
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)
將會話的時區(qū)設(shè)置為UTC時區(qū)再次查詢,ts由于從CST時區(qū)變?yōu)閁TC時區(qū)查詢到的結(jié)果比之前慢8個小時,由于dt不帶時區(qū)信息,結(jié)果不變
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產(chǎn)生的binlog中也有體現(xiàn),ts在binlog中存儲為時間戳(從1970-01-01 00:00:00 UTC到目前的秒數(shù))相當于帶UTC時區(qū)信息,dt為不帶時區(qū)信息,結(jié)果為格式化后的字符串2021-12-05 15:04:13.293949,主要關(guān)注倒數(shù)第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相關(guān)項目時,使用解析MySQL binlog的開源工具,例如github.com/go-mysql-org/go-mysql,如果配置了parseTime=true會將timestamp類型字段解析為Local時間,將datetime類型解析為UTC時間,也可配置為false獲取到的就是字符串(timestamp已轉(zhuǎn)換為會話時區(qū)的時間,datetime就是binlog中原生的字符串)自己解析,如果parseTime=true且不是使用的UTC時間插入的datetime字段,理論上拿到的時間已經(jīng)不正確了,相當于直接將CST的2021-12-05 15:04:13.293949轉(zhuǎn)換為了UTC的2021-12-05 15:04:13.293949,實際上應(yīng)該轉(zhuǎn)換為UTC的2021-12-05 07:04:13.293949才正確
- 如果剛好業(yè)務(wù)需求中有time.Now()獲取的Local時間和datetime類型字段比較的場景,需要注意時區(qū)問題,或者將時間都去掉時區(qū),轉(zhuǎn)換為格式化后的字符串相比較
- 由于datetime本身就不帶時區(qū)信息,除了轉(zhuǎn)換UTC時間,也沒有更好的選擇,所以很坑!
到此這篇關(guān)于詳解MySQL中timestamp和datetime時區(qū)問題導致做DTS遇到的坑的文章就介紹到這了,更多相關(guān)MySQL timestamp和datetime坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL的InnoDB擴容及ibdata1文件瘦身方案完全解析
在使用InnoDB存儲引擎后,MySQL的ibdata1文件常常會占據(jù)大量存儲空間,這里我們就為大家?guī)鞰ySQL的InnoDB擴容及ibdata1文件瘦身方案完全解析:2016-06-06mysql 報錯This function has none of DETERMINISTIC解決方案
這篇文章主要介紹了mysql 報錯This function has none of DETERMINISTIC解決方案的相關(guān)資料,需要的朋友可以參考下2016-11-11Navicat連接MySQL時報10060、1045錯誤及my.ini位置問題
這篇文章主要介紹了Navicat連接MySQL的10060及1045報錯,my.ini位置,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03MySQ索引操作命令總結(jié)(創(chuàng)建、重建、查詢和刪除索引命令詳解)
本篇文章主要是對MySQL索引操作方法做了一下總結(jié),包括創(chuàng)建索引、重建索引、查詢索引、刪除索引的操作2014-04-04