MySQL Server時區(qū)支持的使用
本文介紹MySQL維護的時區(qū)設(shè)置——如何加載命名時間支持所需的系統(tǒng)表,如何及時了解時區(qū)變化,以及如何啟用閏秒支持。
從MySQL 8.0.19開始,插入的日期時間值也支持時區(qū)偏移。
1 時區(qū)變量
MySQL Server維護了幾個時區(qū)設(shè)置:
- 服務(wù)器系統(tǒng)時區(qū)。當(dāng)服務(wù)器啟動時,它會嘗試確定主機的時區(qū),并使用它來設(shè)置system_time_zone系統(tǒng)變量。
- 要在啟動時明確指定MySQL Server的系統(tǒng)時區(qū),請在啟動mysqld之前設(shè)置TZ環(huán)境變量。如果使用mysqld_safe啟動服務(wù)器,其--timezone選項提供了另一種設(shè)置系統(tǒng)時區(qū)的方法。TZ和--時區(qū)的允許值取決于系統(tǒng)。請參閱您的操作系統(tǒng)文檔,了解哪些值是可接受的。
- 服務(wù)器當(dāng)前時區(qū)。全局time_zone系統(tǒng)變量表示服務(wù)器當(dāng)前運行的時區(qū)。初始time_zone值為“system”,表示服務(wù)器時區(qū)與系統(tǒng)時區(qū)相同。
注意:
如果設(shè)置為SYSTEM,則每個需要時區(qū)計算的MySQL函數(shù)調(diào)用都會進行系統(tǒng)庫調(diào)用,以確定當(dāng)前系統(tǒng)時區(qū)。此調(diào)用可能受到全局互斥的保護,從而導(dǎo)致爭用。
初始全局服務(wù)器時區(qū)值可以在啟動時使用命令行上的--default時區(qū)選項顯式指定,也可以在選項文件中使用以下行:
default-time-zone='timezone'
如果您具有SYSTEM_VARIABLES_ADMIN權(quán)限(或不推薦使用的SUPER權(quán)限),則可以使用以下語句在運行時設(shè)置全局服務(wù)器時區(qū)值:
SET GLOBAL time_zone = timezone;
- 每個會話的時區(qū)。每個連接的客戶端都有自己的會話時區(qū)設(shè)置,由會話time_zone變量給定。最初,會話變量的值取自全局time_zone變量,但客戶端可以使用以下語句更改自己的時區(qū):
SET time_zone = timezone;
會話時區(qū)設(shè)置會影響區(qū)分區(qū)域的時間值的顯示和存儲。這包括函數(shù)(如NOW()或CURTIME())顯示的值,以及存儲在TIMESTAMP列中和從中檢索的值。TIMESTAMP列的值從會話時區(qū)轉(zhuǎn)換為UTC用于存儲,從UTC轉(zhuǎn)換為會話時區(qū)用于檢索。
會話時區(qū)設(shè)置不影響UTC_TIMESTAMP()等函數(shù)顯示的值或DATE、time或DATETIME列中的值。這些數(shù)據(jù)類型中的值也不存儲在UTC中;時區(qū)僅在從TIMESTAMP值轉(zhuǎn)換時適用于它們。如果需要DATE、TIME或DATETIME值的特定于區(qū)域設(shè)置的算術(shù)運算,請將它們轉(zhuǎn)換為UTC,執(zhí)行算術(shù)運算,然后再轉(zhuǎn)換回來。
當(dāng)前全局和會話時區(qū)值可以這樣檢索:
SELECT @@GLOBAL.time_zone, @@SESSION.time_zone;
時區(qū)值可以用幾種格式給出,它們都不區(qū)分大小寫:
- 作為值“SYSTEM”,表示服務(wù)器時區(qū)與系統(tǒng)時區(qū)相同。
- 作為一個字符串,指示與UTC的偏移量,格式為[H]H:MM,前綴為+或-,如“+10:00”、“-6:00”或“+05:30”。前導(dǎo)零可以可選地用于小于10的小時值;在這種情況下,MySQL在存儲和檢索值時會預(yù)加一個前導(dǎo)零。MySQL將“-00:00”或“-0:00”轉(zhuǎn)換為“+00:00”。
- 在MySQL 8.0.19之前,此值必須在“-12:59”到“+13:00”之間(包括在內(nèi));從MySQL 8.0.19開始,允許的范圍是“-13:59”到“+14:00”,包括在內(nèi)。
- 作為命名時區(qū),如“歐洲/赫爾辛基”、“美國/東方”、“MET”或“UTC”。
只有當(dāng)mysql數(shù)據(jù)庫中的時區(qū)信息表已經(jīng)創(chuàng)建并填充時,才能使用命名時區(qū)。否則,使用命名時區(qū)會導(dǎo)致錯誤:
mysql> SET time_zone = 'UTC'; ERROR 1298 (HY000): Unknown or incorrect time zone: 'UTC'
2 填充時區(qū)表
mysql系統(tǒng)模式中有幾個表用于存儲時區(qū)信息。MySQL安裝過程會創(chuàng)建時區(qū)表,但不會加載它們。要手動執(zhí)行此操作,請使用以下說明。
注意:
加載時區(qū)信息不一定是一次性操作,因為信息偶爾會發(fā)生變化。當(dāng)發(fā)生此類更改時,使用舊規(guī)則的應(yīng)用程序?qū)⑦^期,您可能會發(fā)現(xiàn)有必要重新加載時區(qū)表,以保持MySQL服務(wù)器使用的信息是最新的。請參閱保持時區(qū)更改的最新狀態(tài)。
如果您的系統(tǒng)有自己的zoneinfo數(shù)據(jù)庫(描述時區(qū)的一組文件),請使用mysql_tzinfo_to_sql程序加載時區(qū)表。這類系統(tǒng)的例子有Linux、macOS、FreeBSD和Solaris。這些文件的一個可能位置是/usr/share/zoneinfo目錄。如果您的系統(tǒng)沒有zoneinfo數(shù)據(jù)庫,您可以使用可下載的軟件包。
要從命令行加載時區(qū)表,請將zoneinfo目錄路徑名傳遞給mysql_tzinfo_To_sql,并將輸出發(fā)送到mysql程序中。例如:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
這里顯示的mysql命令假設(shè)您使用root等帳戶連接到服務(wù)器,該帳戶具有修改mysql系統(tǒng)模式中的表的權(quán)限。根據(jù)需要調(diào)整連接參數(shù)。
mysql_tzinfo_to_sql讀取系統(tǒng)的時區(qū)文件并從中生成sql語句。mysql處理這些語句以加載時區(qū)表。
mysql_tzinfo_to_sql還可以用于加載單個時區(qū)文件或生成閏秒信息:
- 要加載與時區(qū)名稱tz_name對應(yīng)的單個時區(qū)文件tz_file,請調(diào)用mysql_tzinfo_To_sql,如下所示:
mysql_tzinfo_to_sql tz_file tz_name | mysql -u root -p mysql
使用這種方法,必須執(zhí)行一個單獨的命令來加載服務(wù)器需要了解的每個命名區(qū)域的時區(qū)文件。
- 如果您的時區(qū)必須考慮閏秒,請初始化閏秒信息,如下所示,其中tz_file是時區(qū)文件的名稱:
mysql_tzinfo_to_sql --leap tz_file | mysql -u root -p mysql
在運行mysql_tzinfo_to_sql之后,重新啟動服務(wù)器,使其不再繼續(xù)使用任何以前緩存的時區(qū)數(shù)據(jù)。
如果您的系統(tǒng)沒有zoneinfo數(shù)據(jù)庫(例如,Windows),您可以使用一個包含SQL語句的包,該包可在MySQL開發(fā)區(qū)下載:
https://dev.mysql.com/downloads/timezones.html
注意:
如果您的系統(tǒng)有zoneinfo數(shù)據(jù)庫,請不要使用可下載的時區(qū)包。請改用mysql_tzinfo_to_sql實用程序。否則,您可能會導(dǎo)致MySQL和系統(tǒng)上其他應(yīng)用程序在日期時間處理方面存在差異。
要使用已下載的SQL語句時區(qū)包,請對其進行解壓縮,然后將解壓縮后的文件內(nèi)容加載到時區(qū)表中:
mysql -u root -p mysql < file_name
然后重新啟動服務(wù)器。
警告:
不要使用包含MyISAM表的可下載時區(qū)包。這適用于較舊的MySQL版本。MySQL現(xiàn)在使用InnoDB作為時區(qū)表。嘗試用MyISAM表替換它們會導(dǎo)致問題。
3 隨時了解時區(qū)變化
當(dāng)時區(qū)規(guī)則更改時,使用舊規(guī)則的應(yīng)用程序?qū)⑦^期。要保持最新,必須確保您的系統(tǒng)使用當(dāng)前時區(qū)信息。對于MySQL,保持最新狀態(tài)需要考慮多個因素:
- 如果MySQL服務(wù)器的時區(qū)設(shè)置為system,則操作系統(tǒng)時間會影響其使用的時間值。請確保您的操作系統(tǒng)使用的是最新的時區(qū)信息。對于大多數(shù)操作系統(tǒng),最新的更新或service pack會為系統(tǒng)的時間變化做好準(zhǔn)備。請查看操作系統(tǒng)供應(yīng)商的網(wǎng)站,以獲取解決時間更改的更新。
- 如果將系統(tǒng)的/etc/localtime zone文件替換為使用與mysqld啟動時有效的規(guī)則不同的規(guī)則的版本,請重新啟動mysqld,使其使用更新的規(guī)則。否則,當(dāng)系統(tǒng)更改時間時,mysqld可能不會注意到。
- 如果您在MySQL中使用命名時區(qū),請確保MySQL數(shù)據(jù)庫中的時區(qū)表是最新的:
- 如果您的系統(tǒng)有自己的zoneinfo數(shù)據(jù)庫,請在更新zoneinfo時重新加載MySQL時區(qū)表。
- 對于沒有自己的zoneinfo數(shù)據(jù)庫的系統(tǒng),請查看MySQL開發(fā)區(qū)以獲取更新。當(dāng)有新的更新可用時,請下載并使用它來替換當(dāng)前時區(qū)表的內(nèi)容。
mysqld緩存它查找的時區(qū)信息,因此在更新時區(qū)表后,重新啟動mysqld以確保它不會繼續(xù)提供過時的時區(qū)數(shù)據(jù)。
如果您不確定命名時區(qū)是否可用(用作服務(wù)器的時區(qū)設(shè)置或由設(shè)置自己時區(qū)的客戶端使用),請檢查時區(qū)表是否為空。以下查詢確定包含時區(qū)名稱的表是否有任何行:
mysql> SELECT COUNT(*) FROM mysql.time_zone_name; +----------+ | COUNT(*) | +----------+ | 0 | +----------+
計數(shù)為零表示表為空。在這種情況下,當(dāng)前沒有任何應(yīng)用程序使用命名時區(qū),因此不需要更新表(除非您希望啟用命名時區(qū)支持)。計數(shù)大于零表示該表不是空的,并且其內(nèi)容可用于命名時區(qū)支持。在這種情況下,請確保重新加載時區(qū)表,以便使用命名時區(qū)的應(yīng)用程序能夠獲得正確的查詢結(jié)果。
要檢查MySQL安裝是否已針對夏令時規(guī)則的更改進行了正確更新,請使用以下測試。此示例使用的值適用于美國3月11日凌晨2點發(fā)生的2007夏令時1小時變化。
測試使用以下查詢:
SELECT CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central') AS time1, CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central') AS time2;
這兩個時間值表示夏令時更改發(fā)生的時間,使用命名時區(qū)需要使用時區(qū)表。所需的結(jié)果是,兩個查詢都返回相同的結(jié)果(輸入時間,轉(zhuǎn)換為“美國/中部”時區(qū)中的等效值)。
在更新時區(qū)表之前,您會看到如下錯誤結(jié)果:
+---------------------+---------------------+ | time1 | time2 | +---------------------+---------------------+ | 2007-03-11 01:00:00 | 2007-03-11 02:00:00 | +---------------------+---------------------+
更新表格后,您應(yīng)該會看到正確的結(jié)果:
+---------------------+---------------------+ | time1 | time2 | +---------------------+---------------------+ | 2007-03-11 01:00:00 | 2007-03-11 01:00:00 | +---------------------+---------------------+
4 時區(qū)閏秒支持
閏秒值返回的時間部分以:59:59結(jié)束。這意味著像NOW()這樣的函數(shù)可以在閏秒期間連續(xù)兩三秒返回相同的值。確實,時間部分以:59:60或:59:61結(jié)尾的文字時間值被視為無效。
如果有必要在閏秒前一秒搜索TIMESTAMP值,如果將其與“YYYY-MM-DD hh:MM:ss”值進行比較,則可能會獲得異常結(jié)果。下面的示例演示了這一點。它將會話時區(qū)更改為UTC,因此內(nèi)部TIMESTAMP值(以UTC為單位)和顯示值(已應(yīng)用時區(qū)校正)之間沒有差異。
mysql> CREATE TABLE t1 ( a INT, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (ts) ); Query OK, 0 rows affected (0.01 sec) mysql> -- change to UTC mysql> SET time_zone = '+00:00'; Query OK, 0 rows affected (0.00 sec) mysql> -- Simulate NOW() = '2008-12-31 23:59:59' mysql> SET timestamp = 1230767999; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t1 (a) VALUES (1); Query OK, 1 row affected (0.00 sec) mysql> -- Simulate NOW() = '2008-12-31 23:59:60' mysql> SET timestamp = 1230768000; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t1 (a) VALUES (2); Query OK, 1 row affected (0.00 sec) mysql> -- values differ internally but display the same mysql> SELECT a, ts, UNIX_TIMESTAMP(ts) FROM t1; +------+---------------------+--------------------+ | a | ts | UNIX_TIMESTAMP(ts) | +------+---------------------+--------------------+ | 1 | 2008-12-31 23:59:59 | 1230767999 | | 2 | 2008-12-31 23:59:59 | 1230768000 | +------+---------------------+--------------------+ 2 rows in set (0.00 sec) mysql> -- only the non-leap value matches mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:59'; +------+---------------------+ | a | ts | +------+---------------------+ | 1 | 2008-12-31 23:59:59 | +------+---------------------+ 1 row in set (0.00 sec) mysql> -- the leap value with seconds=60 is invalid mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:60'; Empty set, 2 warnings (0.00 sec)
要解決此問題,您可以使用基于實際存儲在列中的UTC值的比較,該值已應(yīng)用閏秒校正:
mysql> -- selecting using UNIX_TIMESTAMP value return leap value mysql> SELECT * FROM t1 WHERE UNIX_TIMESTAMP(ts) = 1230768000; +------+---------------------+ | a | ts | +------+---------------------+ | 2 | 2008-12-31 23:59:59 | +------+---------------------+ 1 row in set (0.00 sec)
到此這篇關(guān)于MySQL Server時區(qū)支持的使用的文章就介紹到這了,更多相關(guān)MySQL Server時區(qū)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL中between...and的使用對索引的影響說明
這篇文章主要介紹了MySQL中between...and的使用對索引的影響說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Mysql實現(xiàn)模糊查詢的兩種方式(like子句?、正則表達式)
通配符是一種特殊語句,主要用來模糊查詢,下面這篇文章主要給大家介紹了關(guān)于給Mysql實現(xiàn)模糊查詢的兩種方式,分別是like子句?、正則表達式,需要的朋友可以參考下2022-09-09MySQL如何從數(shù)據(jù)庫中刪除表中所有數(shù)據(jù)
這篇文章主要介紹了MySQL如何從數(shù)據(jù)庫中刪除表中所有數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06Mysql數(shù)據(jù)庫索引面試題(程序員基礎(chǔ)技能)
索引是Mysql的一塊硬骨頭,但是對于程序猿來說又是十分重要的基礎(chǔ)技能。本文將從索引原理、索引設(shè)計原則方面闡述Mysql索引,相信通過本文的學(xué)習(xí)你將完美征服阿里面試官2021-05-05