sql >> Databasteknik >  >> RDS >> Mysql

Bör MySQL ha sin tidszon inställd på UTC?

Det verkar som att det inte spelar någon roll vilken tidszon som finns på servern så länge du har rätt tid inställd för den aktuella tidszonen, känner till tidszonen för datetime-kolumnerna som du lagrar och är medveten om problemen med sommartid.

Å andra sidan om du har kontroll över tidszonerna för de servrar du arbetar med kan du ha allt inställt på UTC internt och aldrig oroa dig för tidszoner och sommartid.

Här är några anteckningar som jag samlat in om hur man arbetar med tidszoner som en form av cheatsheet för mig själv och andra som kan påverka vilken tidszon personen kommer att välja för sin server och hur han/hon kommer att lagra datum och tid.

MySQL Timezone Cheatsheet

Anmärkningar:

  1. Att ändra tidszonen kommer inte att ändra den lagrade datum- och tidsstämpeln , men det kommer att välja ett annat datum och tid från tidsstämpelkolumnerna

  2. Varning! UTC har skottsekunder, dessa ser ut som '2012-06-30 23:59:60' och kan läggas till slumpmässigt, med 6 månaders varsel, på grund av att jordens rotation saktar ner

  3. GMT förvirrar sekunder, vilket är anledningen till att UTC uppfanns.

  4. Varning! olika regionala tidszoner kan ge samma datum och tid på grund av sommartid

  5. Tidstämpelkolumnen stöder endast datum 1970-01-01 00:00:01 till 2038-01-19 03:14:07 UTC, på grund av en begränsning .

  6. Internt en MySQL-tidsstämpelkolumn lagras som UTC men när du väljer ett datum kommer MySQL automatiskt att konvertera det till den aktuella sessionens tidszon.

    När du lagrar ett datum i en tidsstämpel antar MySQL att datumet är i den aktuella sessionens tidszon och konverterar det till UTC för lagring.

  7. MySQL kan lagra partiella datum i datetime-kolumner, dessa ser ut som"2013-00-00 04:00:00"

  8. MySQL lagrar "0000-00-00 00:00:00" om du ställer in en datetime-kolumn som NULL, om du inte specifikt ställer in kolumnen så att den tillåter null när du skapar den.

  9. Läs detta

För att välja en tidsstämpelskolumn i UTC-format

oavsett vilken tidszon den aktuella MySQL-sessionen är i:

SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime` 
FROM `table_name`

Du kan också ställa in servern eller den globala eller aktuella sessionens tidszon till UTC och sedan välja tidsstämpeln så här:

SELECT `timestamp_field` FROM `table_name`

För att välja aktuell datumtid i UTC:

SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+00:00');

Exempelresultat:2015-03-24 17:02:41

För att välja aktuell datumtid i sessionens tidszon

SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();

För att välja den tidszon som ställdes in när servern startade

SELECT @@system_time_zone;

Returnerar "MSK" eller "+04:00" för Moskva-tid till exempel, det finns (eller fanns) en MySQL-bugg där om den ställdes till en numerisk offset inte skulle justera sommartiden

För att få aktuell tidszon

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Den kommer tillbaka 02:00:00 om din tidszon är +2:00.

För att få den aktuella UNIX-tidsstämpeln (i sekunder):

SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();

För att få tidsstämpelkolumnen som en UNIX-tidsstämpel

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

För att få en UTC-datumtidkolumn som en UNIX-tidsstämpel

SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', @@session.time_zone)) FROM `table_name`

Få en aktuell tidszon datumtid från ett positivt UNIX-tidsstämpeltal

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Få en UTC-datumtid från en UNIX-tidsstämpel

SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), @@session.time_zone, '+00:00') 
FROM `table_name`

Få en aktuell tidszon datumtid från ett negativt UNIX-tidsstämpeltal

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND) 

Det finns tre platser där tidszonen kan ställas in i MySQL:

Obs:En tidszon kan ställas in i två format:

  1. en offset från UTC:'+00:00', '+10:00' eller '-6:00'
  2. som en namngiven tidszon:'Europe/Helsingfors', 'US/Eastern' eller 'MET'

Namngivna tidszoner kan endast användas om tidszonsinformationstabellerna i mysql-databasen har skapats och fyllts i.

i filen "my.cnf"

default_time_zone='+00:00'

eller

timezone='UTC'

@@global.time_zone variabel

För att se vilket värde de är inställda på

SELECT @@global.time_zone;

För att ställa in ett värde för det, använd endera:

SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

@@session.time_zone variabel

SELECT @@session.time_zone;

För att ställa in det, använd endera:

SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

både "@@global.time_zone variabel" och "@@session.time_zone variabel" kan returnera "SYSTEM" vilket betyder att de använder tidszonen som är inställd i "my.cnf".

För att tidszonnamn ska fungera (även för standardtidszon) måste du ställa in dina tidszonsinformationstabeller måste fyllas i: http://dev.mysql.com/doc /refman/5.1/en/time-zone-support.html

Obs:du kan inte göra detta eftersom det kommer att returnera NULL:

SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime` 
FROM `table_name`

Ställ in mysql-tidszonstabeller

För CONVERT_TZ för att fungera måste du fylla i tidszonstabellerna

SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;

Om de är tomma, fyll sedan i dem genom att köra det här kommandot

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

om detta kommando ger dig felet "data för lång för kolumn 'förkortning' på rad 1 ", då kan det bero på att ett NULL-tecken läggs till i slutet av tidszonens förkortning

korrigeringen är att köra detta

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql

echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql

mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql

(se till att dina servrars dst-regler är uppdaterade zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time- on-linux/ )

Se hela övergångshistoriken för sommartid (sommartid) för varje tidszon

SELECT 
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND)  AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC

CONVERT_TZ tillämpar även alla nödvändiga ändringar i sommartid baserat på reglerna i ovanstående tabeller och datumet som du använder.

Obs!
Enligt dokumenten , värdet du anger för tidszon ändras inte, om du ställer in det som "+01:00" till exempel, kommer tidszonen att ställas in som en offset från UTC, som inte följer sommartid, så den kommer att förbli densamma alla året runt.

Endast de namngivna tidszonerna kommer att ändra tid under sommartid.

Förkortningar som CET kommer alltid att vara en vintertid och CEST kommer att vara sommartid medan +01:00 alltid kommer att vara UTC tid + 1 timme och båda ändras inte med sommartid.

system tidszon kommer att vara tidszonen för värddatorn där mysql är installerat (såvida inte mysql inte kan fastställa det)

Du kan läsa mer om att arbeta med sommartid här

När ska man inte använda UTC av den legendariska Jon Skeet:https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/ (Till exempel en schemalagd händelse i framtiden som representerar en tid, inte ett ögonblick i tiden)

relaterade frågor:

Källor:



  1. SQL Server - definierar en XML-typkolumn med UTF-8-kodning

  2. Du, vem äger det där #temp-bordet?

  3. SQL TRUNCATE-syntax – listad av DBMS

  4. 4 sätt att lista alla vyer i en MariaDB-databas