數據庫時區那些事兒 - MySQL的時區處理

原文地址

當JVM時區和數據庫時區不一致的時候,會發生什么?這個問題也許你從來沒有注意過,但是當把Java程序容器化的時候,問題就浮現出來了,因為目前幾乎所有的Docker Image的時區都是UTC。本文探究了MySQL及其JDBC驅動對于時區的處理方式,并嘗試給出最佳實踐。

先給總結

  • DATETIME類型不支持時區轉換。
  • 對于TIMESTAMP類型,MySQL會正確的根據connection時區(對于JDBC來說就是JVM時區)/服務端時區做轉換。

    • JDBC程序不需要特別注意什么事情。只要保證JVM時區和用戶所在時區保持一致即可。
  • 不要在服務器端做日期時間的字符串格式化(DATE_FORMAT()),因為返回的結果是服務端的時區,而不是connection的時區(對于JDBC來說就是JVM時區)。
  • CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE()可以安全的使用,返回的結果會轉換成connection時區(對于JDBC來說就是JVM時區)。
  • CURRENT_TIME()有一個不知道是不是BUG的Bug #92453。

日期時間類型的時區

MySQL - The DATE, DATETIME, and TIMESTAMP Types:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the
current time zone for retrieval. (This does not occur for other types such as DATETIME.)
By default, the current time zone for each connection is the server's time. The time zone can be set on
a per-connection basis.
As long as the time zone setting remains constant, you get back the same value you store.
If you store a TIMESTAMP value, and then change the time zone and retrieve the value, the retrieved value
is different from the value you stored. This occurs because the same time zone was not used for conversion
in both directions.

簡而言之就是兩句話:

  1. 查詢TIMESTAMP類型所返回的值,會根據connection的時區(對于JDBC來說就是JVM時區)做轉換
  2. 在MySQL中只有TIMESTAMP類型會做時區轉換

為了驗證這個結論,我寫了一段程序來實驗,這個程序做了三件事情:

  1. 使用Asia/Shanghai時區構造一個日期java.util.Date2018-09-14 10:00:00,然后插入到數據庫里(表:test,列:timestamp類型)
  2. 使用Asia/Shanghai時區把這個值再查出來,看看結果。
  3. 使用Asia/Shanghai時區,獲得這個字段的格式化字符串(使用DATE_FORMAT()函數)。
  4. 使用Europe/Paris時區重復第2-3步的動作

在運行程序之前,我們先用Docker啟動一個MySQL,它所在的MySQL的時區是UTC(除非特別設定,所有Docker Image時區都默認為UTC):

docker run --name mysql-timezone-test \-e MYSQL_RANDOM_ROOT_PASSWORD=yes \-e MYSQL_DATABASE=testdb \-e MYSQL_USER=tz \-e MYSQL_PASSWORD=tz \-p 3306:3306 \-d mysql:8

下面是結果:

Insert data, Time Zone        : 中國標準時間
java.util.Date                : 2018-09-14 10:00:00
Insert into timestamp column  : 2018-09-14 10:00:00
--------------------
Retrieve data, Time Zone      : 中國標準時間
Retrieve java.util.Date       : 2018-09-14 10:00:00
Retrieve formatted string     : 2018-09-14 02:00:00
--------------------
Retrieve data, Time Zone      : 中歐時間
Retrieve java.util.Date       : 2018-09-14 04:00:00
Retrieve formatted string     : 2018-09-14 02:00:00

可以看到Retrieve java.util.Date返回的結果根據JVM時區做了轉換的。而Retrieve formatted string返回的結果則是UTC時間。

當前日期時間相關函數

MySQL與"當前日期時間"相關的函數有這么些,MySQL - Date and Time Functions:

The CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE(), and FROM_UNIXTIME() functions return values
in the connection's current time zone, which is available as the value of the time_zone system variable.

而且根據文檔所講,它們返回的結果匹配當前連接所設定的時區。

為了驗證這個結論,同樣寫了一段程序,分別使用Asia/ShanghaiEurope/Paris來調用CURRENT_TIMESTAMP()CURRENT_TIME()CURRENT_DATE()

下面是運行結果:

JVM Time Zone              : 中國標準時間
Test CURRENT_DATE()        : 2018-09-18
Test CURRENT_TIME()        : 10:55:41
Test CURRENT_TIMESTAMP()   : 2018-09-18 10:55:41.0
--------------------
JVM Time Zone              : 中歐時間
Test CURRENT_DATE()        : 2018-09-18
Test CURRENT_TIME()        : 03:56:02
Test CURRENT_TIMESTAMP()   : 2018-09-18 04:56:02.0

可以看到結果是基本符合文檔里的說明的,但是要注意,在Europe/Paris時區,CURRENT_TIME()CURRENT_TIMESTAMP()的時間部分相差一小時。
看上去CURRENT_TIMESTAMP()返回的是UTC DST offset結果,而CURRENT_TIME()返回的是UTC offset結果,關于這個我登記了Bug #92453。
關于Europe/Paris的DST信息可以在這里找到Wiki - List of tz database time zones。

在MySQL客戶端操作時區

-- 查詢系統時區和session時區
SELECT @@global.time_zone, @@session.time_zone;-- 設置session時區
SET time_zone = 'Asia/Shanghai';

詳見:MySQL Server Time Zone Support

Docker啟動時設定時區

你可以在docker啟動的時候設定MySQL容器的時區,比如這樣-e TZ=Asia/Shanghai

這個方法有問題,會出現時間錯亂,workaround是root用戶連接到MySQL,然后執行SET GLOBAL time_zone = 'Asia/Shanghai';

這樣客戶端連接MySQL時,查詢的時間的時區都是Asia/Shanghai了。

參考資料

  • MySQL - The DATE, DATETIME, and TIMESTAMP Types
  • MySQL - Date and Time Functions
  • MySQL Server Time Zone Support
  • Wiki - List of tz database time zones
  • W3C- Working with timezone

相關代碼

https://github.com/chanjarste...

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282109.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282109.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282109.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java_函數的重載

函數的重載(Overload)概念:在同一個類中,允許存在一個以上的同名函數,只要他們的參數個數或者參數類型不同即可。函數功能一樣,僅僅是參與運算的未知內同不同時,可以定義多函數,卻使…

全新升級的AOP框架Dora.Interception[2]: 基于約定的攔截器定義方式

Dora.Interception(github地址,覺得不錯不妨給一顆星)有別于其他AOP框架的最大的一個特點就是采用針對“約定”的攔截器定義方式。如果我們為攔截器定義了一個接口或者基類,那么攔截方法將失去任意注冊依賴服務的靈活性。除此之外…

redis watch使用場景_redis不得不會的事務玩法

我們都知道redis追求的是簡單,快速,高效,在這種情況下也就拒絕了支持window平臺,學sqlserver的時候,我們知道事務還算是個比較復雜的東西,所以這吊毛要是照搬到redis中去,理所當然redis就不是那…

加快Android Studio的編譯速度

從Eclipse切換到Android Studio后,感覺Android Studio的build速度比Eclipse慢很多,以下幾個方法可以提高Android Studio的編譯速度使用Gradle 2.4Gradle 2.4對執行性能有很大的優化,但Android Studio現在默認使用的是Gradle 2.2,所以我們需要…

開發中 MySQL 規范

一、建表規范 1、數據庫名、表名、字段名必須使用小寫字母或數字,并且禁止以數字開頭 示例:goods_category、agent_operate_201812_log 2、數據庫名、表名、字段名要做到見名識意 示例:goods_category,不能 gc 3、配置表建議以 …

PaddleOCR在 Linux下的webAPI部署方案

很多小伙伴在使用OCR時都希望能采用API的方式調用,這樣就可以跨端跨平臺了。本文將介紹一種基于python的PaddleOCR識別WebAPI部署方案。喜歡的可以關注公眾號,獲取更多內容。一、 Linux環境下部署1.環境要求操作系統:CenterOS7;主…

影響程序員生涯的三個錯誤觀念,你千萬不要犯!

程序員在社會上,到底是怎樣一個生活群體?是否能找到自己方向?其實,路一直都在那里,只是你看不到而已! 當初的你,可能一直被一些技術牽著鼻子走,并不是自己在做著自己想做的&#xff…

心電圖計算心率公式_心電圖到底能反應啥問題,看過之后你也能當“醫生”

只要是經歷過健康體檢的健康人,或者做過手術的患者,基本都做過心電圖檢查。都說久病成醫,所以有些人對血、尿常規等各項檢查的結果都門清兒得很,最起碼看一眼也能說出個大概齊。偏偏心電圖這種常做的檢查,不但老病號如…

獲取正在運行的服務

手機上安裝的App,在后臺運行著很多不同功能的服務,最常見的例如消息推送相關的服務。如何查看這些服務?如何判斷某個服務是否正在運行?如何停止某一個服務呢?請看下面的方法: package com.example.servicel…

openstack的vnc啟動ssl

1、制作ssl證書# cd /etc/pki/tls/certs [rootwww certs]# make vnc.key Enter pass phrase:# 輸入密碼 Verifying - Enter pass phrase:#確認# 從private key 中刪除密碼# openssl rsa -in vnc.key -out vnc.key # make vnc.csr Country Name (2 letter code) [XX]:CN# 國家 S…

開發composer包

一、初始化&#xff08;生成composer.json文件&#xff09; composer init#輸入你要創建的composer包項目命名空間 Package name (<vendor>/<name>) [root/tiny-laravel]: #haveyb/tiny-laravel #輸入composer包的描述 Description []:#this is a tiny laravel h…

Linux本地yum源配置以及使用yum源安裝gcc編譯環境

本文檔是圖文安裝本地yum源的教程&#xff0c;以安裝gcc編譯環境為例。 適用范圍&#xff1a;所有的cetos,紅帽,fedroa版本 適用人群&#xff1a;有一點linux基礎的小白 范例系統版本&#xff1a;CentOS Linux release 7.3.1611 (Core) 范例環境&#xff1a;vmware 虛擬機 安裝…

word如何設置上標形式_如何在word中設置特殊頁碼

獲取更多業界資訊和深度好文● 點擊藍字關注我們 ●在日常工作中&#xff0c;我們編輯的word文檔經常需要設置頁碼&#xff0c;但有時文檔的第一頁是封面&#xff0c;第二頁才是正文&#xff0c;或者第二頁是目錄&#xff0c;第三頁才是正文&#xff0c;如下圖所示&#xff0c;…

[cf797c]Minimal string(貪心+模擬)

題意&#xff1a; 給出了字符串s的內容&#xff0c;字符串t&#xff0c;u初始默認為空&#xff0c;允許做兩種操作&#xff1a; 1、把s字符串第一個字符轉移到t字符串最后 2、把t字符串最后一個字符轉移到u字符串最后 最后要求s、t字符串都為空&#xff0c;問u字符串字典序最小…

發布composer包到 Packagist,并設置自動同步(從github到Packagist)

一、發布composer包 1、將我們寫好的項目包發布到github上 這一步不贅述&#xff0c;應該都會。 但是需要注意的是&#xff0c;我們一定要為我們的項目包打上tag之后再提交&#xff0c;否則 我們composer require時可能會報錯 Could not find a version of package。 # 設置…

教你在CorelDRAW中導入位圖

在CorelDRAW軟件中不能直接打開位圖圖像&#xff0c;在實際操作中&#xff0c;用戶需要使用導入位圖圖像的方法進行操作。導入位圖圖像時&#xff0c;可以導入整幅圖像&#xff0c;也可以在導入的過程中對圖像進行裁剪&#xff0c;或重新取樣圖像&#xff0c;導入整幅位圖圖像時…

.NET 6 中將 ASP.NET Core 注冊成 Windows Service

前言使用 Visual Studio 中的 Worker Service項目模板:我們很容易創建出 Windows Service&#xff1a;IHost host Host.CreateDefaultBuilder(args).UseWindowsService().ConfigureServices(services >{services.AddHostedService<Worker>();}).Build();await host.R…

19.12 添加自定義監控項目 配置郵件告警 測試告警

9月12日任務19.12 添加自定義監控項目19.13/19.14 配置郵件告警19.15 測試告警19.16 不發郵件的問題處理19.12 添加自定義監控項目需求&#xff1a;監控某臺web的80端口連接數&#xff0c;并出圖兩步&#xff1a;1&#xff09;zabbix監控中心創建監控項目&#xff1b;2&#xf…

wab框架

http協議 一、http簡介 1.HTTP是一個基于TCP/IP通信協議來傳遞數據&#xff08;HTML 文件, 圖片文件, 查詢結果等&#xff09;。 2.HTTP是一個屬于應用層的面向對象的協議&#xff0c;由于其簡捷、快速的方式&#xff0c;適用于分布式超媒體信息系統。它于1990年提出&#xff0…

c++ 二維矩陣 轉vector_Python線性代數學習筆記——矩陣的基本運算和基本性質,實現矩陣的基本運算...

當學習完矩陣的定義以后&#xff0c;我們來學習矩陣的基本運算&#xff0c;與基本性質矩陣的基本運算&#xff1a;矩陣的加法&#xff0c;每一個對應元素相加&#xff0c;對應結果的矩陣例子&#xff1a;矩陣A和矩陣B表示的是同學上學期和下學期的課程的成績&#xff0c;兩個矩…