MySQL | 如何理解並解決後端請求數據時間相差八小時

情況描述

MySQL數據庫中存儲的爲Date類型的數據,數據取出後,時間變爲2017-09-02T16:00:00.000Z。後端(node)返回給前端的數據與實際數據相差八小時。如果直接截取字符串,就會出現和實際數據相差一天的魔幻情況
在這裏插入圖片描述


原因分析

T, Z分別表示什麼意思?

T,分隔時間和日期,沒有特殊含義
Z,表示爲零時區時間

> new Date('2017-09-02T16:00:00.000Z')
  Sun Sep 03 2017 00:00:00 GMT+0800 (中國標準時間)

哪個環節的時間出了問題?

首先了解DATE, DATETIME,TIMESTAMP三種類型的處理方式

MySQL將TIMESTAMP值從當前時區轉換爲UTC進行存儲,然後從UTC返回當前時區進行檢索。(對於其他類型,例如DATETIME。不會發生這種情況。)默認情況下,每個連接的當前時區是服務器的時間。
來源:MySQL 8.0參考手冊
見下方參考鏈接1

官方文檔中的描述,並沒有解釋DATE類型出現這種問題的原因

In mysql, DATE and DATETIME are stored as simple strings. They are also sent and received as strings, without any regard for timezones.
The mysql package, however, will by default try to convert these types into Date objects. This is pretty much just wrong since DATETIME and DATE don’t have timezones, whereas Date objects do.
來源:見下方參考鏈接2

MySQL包會默認嘗試將DATE,DATETIME數據類型轉換爲DATE對象,而DATE對象會考慮時區
在這裏插入圖片描述
使用SHOW VARIABLES LIKE "%time_zone%";後,可以查看當前有關時區的設置
服務器時區設置會影響結果,只有時區設置保持不變,纔會得到正確的日期


解決辦法

路線一:後天改造

問題轉換爲怎麼把“2017-09-02T16:00:00.000Z”變成"2017-09-03"

①使用Date對象的toLocaleDateString()方法

如果爲字符串,先轉換爲對象,調用方法,之後重新賦值即可。以下爲示例代碼。

let date1 = '2019-03-09T16:00:00.000Z';
let date2 = new Date(date1);
console.log(typeof(date2)); //對Date對象進行操作
let date3 = date2.toLocaleDateString();
console.log(date2, date3);
//結果
object
2019-03-09T16:00:00.000Z 2019-3-10
②使用moment.js

前端,後端都可以處理
前端

npm install moment //安裝

示例代碼

let term = re.term[0];
console.log('before:', term);
term.sdate = moment(term.sdate).format("YYYY-MM-DD");
console.log('after', term);
//結果
before: {sdate: "2017-09-02T16:00:00.000Z"}
after {sdate: "2017-09-03"}

後端

node install moment --save //安裝

使用方法,參照前端代碼

路線二:先天改造

問題轉換爲怎麼阻止出現“2017-09-02T16:00:00.000Z”

①設置DATETIMEDATE以字符串返回

在設置數據庫的部分,加入dateString

let config = {
    // ...
    dateStrings: [
        'DATE',
        'DATETIME'
    ]
}
let pool = mysql.createPool(config)
②設置系統區時

linux系統的話,將系統區時設置到中國上海。具體方法參見後端 Date 時間 傳到前端,相差8小時原因二部分。
Window嗎?…你說啥?我信號不好…
此方法未實驗成功,歡迎補充!orz


總結

如果考慮時區,使用TIMESTAMP類型;如果不考慮,使用VARCHAR類型
使用DATEDATETIME類型使用時,小心類型轉換的情況

TIMESTAMPDATETIME類型的比較對比參見 關於“時間”的一次探索


寫在最後

這問題出現之後,採用路線一種的思維,解決so easy,不用花太久時間,但是一仔細想原因,琢磨了很久(菜是原罪orz)。也不知道有沒有想這麼久的必要,希望能幫助到苦惱這個問題的人!在解決的同時想明白真的非常開心 哈哈哈!


參考文章

①原因理解(建議按順序瀏覽)
1.11.2.2 DATE,DATETIME和TIMESTAMP類型
2.Gotcha! Timezones in nodejs and mysql 強烈推薦!!
3.關於“時間”的一次探索
②解決辦法
4.後端 Date 時間 傳到前端,相差8小時
5.JavaScript UTC時間轉換
6.JavaScript Date 對象
7.node請求mysql數據庫,時間差八個小時問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章