sql >> Database teknologi >  >> RDS >> Mysql

Skal MySQL have sin tidszone indstillet til UTC?

Det lader til, at det er ligegyldigt, hvilken tidszone der er på serveren, så længe du har den rigtige tid indstillet til den aktuelle tidszone, kender tidszonen for de datetime-kolonner, du gemmer, og er opmærksom på problemerne med sommertid.

På den anden side, hvis du har kontrol over tidszonerne på de servere, du arbejder med, kan du få alt sat til UTC internt og aldrig bekymre dig om tidszoner og sommertid.

Her er nogle noter, jeg har samlet om, hvordan man arbejder med tidszoner som en form for cheatsheet for mig selv og andre, som kan have indflydelse på, hvilken tidszone personen vil vælge til sin server, og hvordan han/hun gemmer dato og klokkeslæt.

MySQL Timezone Cheatsheet

Bemærkninger:

  1. Ændring af tidszonen vil ikke ændre det gemte dato og klokkeslæt eller tidsstemplet , men det vil vælge en anden dato og klokkeslæt fra tidsstempelkolonner

  2. Advarsel! UTC har skudsekunder, disse ser ud som '2012-06-30 23:59:60' og kan tilføjes tilfældigt med 6 måneders varsel på grund af afmatningen af ​​jordens rotation

  3. GMT forvirrer sekunder, og derfor blev UTC opfundet.

  4. Advarsel! Forskellige regionale tidszoner producerer muligvis den samme dato og klokkeslæt på grund af sommertid

  5. Tidsstempelkolonnen understøtter kun datoer 1970-01-01 00:00:01 til 2038-01-19 03:14:07 UTC, på grund af en begrænsning .

  6. Internt en MySQL-tidsstempelkolonne er gemt som UTC men når du vælger en dato, vil MySQL automatisk konvertere den til den aktuelle sessions tidszone.

    Når du gemmer en dato i et tidsstempel, vil MySQL antage, at datoen er i den aktuelle sessions tidszone og konvertere den til UTC for lagring.

  7. MySQL kan gemme delvise datoer i datetime-kolonner, disse ser ud som"2013-00-00 04:00:00"

  8. MySQL gemmer "0000-00-00 00:00:00", hvis du indstiller en datetime-kolonne som NULL, medmindre du specifikt indstiller kolonnen til at tillade null, når du opretter den.

  9. Læs dette

For at vælge en tidsstempelkolonne i UTC-format

uanset hvilken tidszone den aktuelle MySQL-session er i:

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

Du kan også indstille serveren eller den globale eller aktuelle sessions tidszone til UTC og derefter vælge tidsstemplet sådan:

SELECT `timestamp_field` FROM `table_name`

Sådan vælger du den aktuelle dato og klokkeslæt i UTC:

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

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

For at vælge den aktuelle dato og klokkeslæt i sessionens tidszone

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

For at vælge den tidszone, der blev indstillet, da serveren startede

SELECT @@system_time_zone;

Returnerer "MSK" eller "+04:00" for Moskva-tid for eksempel, der er (eller var) en MySQL-fejl, hvor den, hvis den er indstillet til en numerisk offset, ikke ville justere sommertiden

For at få den aktuelle tidszone

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Den vender tilbage 02:00:00, hvis din tidszone er +2:00.

For at få det aktuelle UNIX-tidsstempel (i sekunder):

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

For at få tidsstempelkolonnen som et UNIX-tidsstempel

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

For at få en UTC-dato-tidskolonne som et UNIX-tidsstempel

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

Få en aktuel tidszone dato/klokkeslæt fra et positivt UNIX-tidsstempel-heltal

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Få en UTC-datotid fra et UNIX-tidsstempel

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

Få en aktuel tidszone dato/klokkeslæt fra et negativt UNIX-tidsstempel-heltal

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

Der er 3 steder, hvor tidszonen kan indstilles i MySQL:

Bemærk:En tidszone kan indstilles i 2 formater:

  1. en offset fra UTC:'+00:00', '+10:00' eller '-6:00'
  2. som en navngivet tidszone:'Europe/Helsinki', 'US/Eastern' eller 'MET'

Navngivne tidszoner kan kun bruges, hvis tidszoneinformationstabellerne i mysql-databasen er blevet oprettet og udfyldt.

i filen "my.cnf"

default_time_zone='+00:00'

eller

timezone='UTC'

@@global.time_zone variabel

For at se, hvilken værdi de er sat til

SELECT @@global.time_zone;

For at indstille en værdi for det, brug enten en:

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;

For at indstille det, brug enten en:

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

både "@@global.time_zone variable" og "@@session.time_zone variable" returnerer muligvis "SYSTEM", hvilket betyder, at de bruger tidszonen indstillet i "my.cnf".

For at tidszonenavne skal fungere (selv for standardtidszone), skal du konfigurere dine tidszoneoplysninger, der skal udfyldes: http://dev.mysql.com/doc /refman/5.1/da/time-zone-support.html

Bemærk:du kan ikke gøre dette, da det vil returnere NULL:

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

Opsæt mysql-tidszonetabeller

For CONVERT_TZ for at fungere, skal tidszonetabellerne udfyldes

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` ;

Hvis de er tomme, så fyld dem op ved at køre denne kommando

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

hvis denne kommando giver dig fejlen "data for lange til kolonne 'forkortelse' i række 1 ", så kan det være forårsaget af et NULL-tegn, der er tilføjet i slutningen af ​​tidszoneforkortelsen

rettelsen er at køre dette

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

(sørg for, at dine servers dst-regler er opdaterede zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time- on-linux/ )

Se hele DST (sommertid) overgangshistorik for hver tidszone

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 anvender også alle nødvendige sommertidsændringer baseret på reglerne i ovenstående tabeller og den dato, du bruger.

Bemærk:
Ifølge dokumenterne , den værdi du indstiller for time_zone ændres ikke, hvis du indstiller den som "+01:00" for eksempel, så vil tidszonen blive sat som en offset fra UTC, som ikke følger sommertid, så den forbliver den samme alle året rundt.

Kun de navngivne tidszoner vil ændre tid i sommertid.

Forkortelser som CET vil altid være en vintertid og CEST vil være sommertid, mens +01:00 altid vil være UTC tid + 1 time, og begge vil ikke ændre sig med sommertid.

system tidszone vil være tidszonen på værtsmaskinen, hvor mysql er installeret (medmindre mysql ikke kan bestemme det)

Du kan læse mere om at arbejde med sommertid her

Hvornår skal man ikke bruge UTC af den legendariske Jon Skeet:https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/ (For eksempel en planlagt begivenhed i fremtiden, der repræsenterer et tidspunkt, ikke et øjeblik i tid)

relaterede spørgsmål:

Kilder:



  1. Enum i Hibernate, fortsætter som en enum

  2. Jeg bliver ved med at få fejlrelationen [TABEL] eksisterer ikke

  3. Hvordan medtager man nul/0 resultater i COUNT aggregat?

  4. Hvordan henter man den første og sidste post af en grupperet post i en MySQL-forespørgsel med aggregerede funktioner?