MySQL dovrebbe avere il fuso orario impostato su UTC?


149

Domanda di follow-up di /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

Il fuso orario di MySQL deve essere impostato su UTC o deve essere impostato sullo stesso fuso orario del server o del PHP? (Se non è UTC)

Quali sono i pro e i contro?


stackoverflow.com/a/1650406/175071 condivide buoni motivi per utilizzare UTC
Timo Huovinen

UTC non è un fuso orario. UTC è uno standard, GMT è un fuso orario. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev

Un altro ottimo motivo per usare UTC dba.stackexchange.com/questions/161416/…
Timo Huovinen il

Risposte:


533

Sembra che non importa quale fuso orario sia sul server, purché tu abbia il tempo impostato correttamente per il fuso orario corrente, conosci il fuso orario delle colonne del datetime che memorizzi e sei consapevole dei problemi con l'ora legale.

D'altra parte, se hai il controllo dei fusi orari dei server con cui lavori, puoi avere tutto impostato su UTC internamente e non preoccuparti mai dei fusi orari e dell'ora legale.

Ecco alcune note che ho raccolto su come lavorare con i fusi orari come una forma di cheatsheet per me e gli altri che potrebbero influenzare il fuso orario che la persona sceglierà per il suo server e come memorizzerà la data e l'ora.

MySQL Timezone Cheatsheet

Appunti:

  1. La modifica del fuso orario non cambierà il datetime o il timestamp memorizzati , ma selezionerà un datetime diverso dalle colonne timestamp
  2. Avvertimento! L'UTC ha secondi da saltare, questi sembrano "2012-06-30 23:59:60" e possono essere aggiunti in modo casuale, con un preavviso di 6 mesi, a causa del rallentamento della rotazione terrestre
  3. GMT confonde i secondi, motivo per cui è stato inventato UTC.

  4. Avvertimento! fusi orari regionali diversi potrebbero produrre lo stesso valore di data / ora a causa dell'ora legale

  5. La colonna timestamp supporta solo le date dal 1970-01-01 00:00:01 al 2038-01-19 03:14:07 UTC, a causa di una limitazione .
  6. Internamente una colonna timestamp MySQL viene memorizzata come UTC ma quando si seleziona una data MySQL la convertirà automaticamente nel fuso orario della sessione corrente.

    Quando si memorizza una data in un timestamp, MySQL supporrà che la data sia nel fuso orario della sessione corrente e la converta in UTC per l'archiviazione.

  7. MySQL può memorizzare date parziali in colonne datetime, queste assomigliano a "2013-00-00 04:00:00"
  8. MySQL memorizza "0000-00-00 00:00:00" se imposti una colonna datetime come NULL, a meno che non imposti la colonna specificatamente per consentire null quando la crei.
  9. Leggi questo

Per selezionare una colonna timestamp in formato UTC

indipendentemente dal fuso orario in cui si trova l'attuale sessione MySQL:

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

Puoi anche impostare il fuso orario della sessione sever o globale o corrente su UTC e quindi selezionare il timestamp in questo modo:

SELECT `timestamp_field` FROM `table_name`

Per selezionare il datetime corrente in UTC:

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

Risultato di esempio: 2015-03-24 17:02:41

Per selezionare il datetime corrente nel fuso orario della sessione

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

Per selezionare il fuso orario impostato all'avvio del server

SELECT @@system_time_zone;

Restituisce "MSK" o "+04: 00" per l'ora di Mosca, ad esempio, c'è (o c'era) un bug MySQL in cui se impostato su un offset numerico non regolerebbe l'ora legale

Per ottenere il fuso orario corrente

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Restituirà 02:00:00 se il fuso orario è +2: 00.

Per ottenere il timestamp UNIX corrente (in secondi):

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

Per ottenere la colonna timestamp come timestamp UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Per ottenere una colonna datetime UTC come data / ora UNIX

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

Ottieni un datetime di fuso orario corrente da un numero intero di data / ora UNIX positivo

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Ottieni un datetime UTC da un timestamp UNIX

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

Ottieni un datetime di fuso orario corrente da un numero intero di data / ora UNIX negativo

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

Ci sono 3 posti in cui il fuso orario potrebbe essere impostato in MySQL:

Nota: un fuso orario può essere impostato in 2 formati:

  1. un offset da UTC: '+00: 00', '+10: 00' o '-6: 00'
  2. come fuso orario denominato: "Europa / Helsinki", "Stati Uniti / Est" o "MET"

I fusi orari nominati possono essere utilizzati solo se le tabelle di informazioni sul fuso orario nel database mysql sono state create e popolate.

nel file "my.cnf"

default_time_zone='+00:00'

o

timezone='UTC'

@@ variabile global.time_zone

Per vedere a quale valore sono impostati

SELECT @@global.time_zone;

Per impostare un valore per esso utilizzare uno dei due:

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

@@ session.time_zone variabile

SELECT @@session.time_zone;

Per impostarlo utilizzare uno dei due:

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

sia "@@ variabile globale.time_zone" che "@@ session.time_zone variabile" potrebbero restituire "SISTEMA", il che significa che usano il fuso orario impostato in "my.cnf".

Affinché i nomi di fuso orario funzionino (anche per il fuso orario predefinito) è necessario impostare le tabelle di informazioni sul fuso orario che devono essere popolate: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. html

Nota: non puoi farlo poiché restituirà NULL:

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

Imposta le tabelle del fuso orario mysql

Per CONVERT_TZfunzionare, è necessario compilare le tabelle del fuso orario

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

Se sono vuoti, riempili eseguendo questo comando

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

se questo comando fornisce l'errore " dati troppo lunghi per la colonna" abbreviazione "nella riga 1 ", potrebbe essere causato da un carattere NULL che viene aggiunto alla fine dell'abbreviazione del fuso orario

la correzione è eseguire questo

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

(assicurati che le regole del tuo server dst siano aggiornate zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Vedi la cronologia completa delle transizioni di ora legale (ora legale) per ogni fuso orario

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 applica inoltre tutte le modifiche necessarie all'ora legale in base alle regole nelle tabelle sopra e alla data in uso.

Nota:
secondo i documenti , il valore impostato per time_zone non cambia, se lo si imposta come "+01: 00", ad esempio, allora time_zone verrà impostato come offset da UTC, che non segue l'ora legale, quindi rimarrà lo stesso tutto l'anno.

Solo i fusi orari indicati cambieranno l'ora durante l'ora legale.

Abbreviazioni come CETsarà sempre un orario invernale e CESTsarà l' UTCora legale mentre +01: 00 sarà sempre l' ora + 1 ora ed entrambe non cambieranno con l'ora legale.

Il systemfuso orario sarà il fuso orario della macchina host in cui è installato mysql (a meno che mysql non riesca a determinarlo)

Puoi leggere di più su come lavorare con l'ora legale qui

domande correlate:

fonti:


Quindi se ho il mio tipo di colonna impostato su timestamp. E il mio fuso orario è +12: 00 e voglio aggiornare una colonna usando una data / ora basata su utc, c'è un modo per includere il fuso orario nell'istruzione di aggiornamento o dovrei usare convert_tz. Per esempio. update tableset modified= '2016-07-07 08:10 +00: 00'
bumperbox

2
@bumperbox mysql presuppone sempre che la data indicata nella colonna timestamp sia nello stesso fuso orario del server mysql, quindi è necessario convertire la data dal fuso orario +12: 00 al fuso orario del server mysql per l'aggiornamento. Questo è il motivo per cui utilizzo UTC sul server mysql e converto qualsiasi data in UTC prima di memorizzarla.
Timo Huovinen,

5
Una delle risposte migliori e più informative che ho trovato in anni di utilizzo di SO. Grazie.
Mitya,

AVVERTIMENTO!!! Qualsiasi utilizzo o conversione dall'ora locale in un fuso orario di ora legale sarà errato di un'ora per un'ora ogni anno alla fine dell'ora legale. Ciò influisce su UNIX_TIMESTAMP(NOW());tutti gli usi del punto in CONVERT_TZ()cui uno dei parametri è `@@ session.time_zone. Per convertire in modo affidabile i periodi di tempo UTC in timestamp UNIX, è necessario impostare prima la sessione time_zone.
Doin,

1
@Flimm assolutamente bene, mi sono dimenticato di sistemarlo qualche tempo fa.
Timo Huovinen,

3

Questo è un esempio funzionante:

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow

2

PHP e MySQL hanno le proprie configurazioni di fuso orario predefinite. È necessario sincronizzare il tempo tra la base di dati e l'applicazione Web, altrimenti si potrebbero verificare alcuni problemi.

Leggi questo tutorial: Come sincronizzare i fusi orari PHP e MySQL


Fondamentalmente sono due righe di codice: date_default_timezone_set("America/Los_Angeles");e ha funzionato in modo mysql_query("SET time_zone='" . date('P', time()) . "'");molto elegante!
Noumenon,

3
@Noumenon Attento! Mi sono grattato la testa stamattina perché è esattamente quello che stavo facendo e alcuni dei miei tempi sono scaduti da un'ora. Ciò di cui sospetto è che l'uso di un fuso orario denominato sia più preciso quando è coinvolto l'ora legale. Se usi America / New_York, MySQL conosce l'ora legale e memorizza le date in modo appropriato. Se lo hai impostato su -04: 00 come hai fatto qui, non prenderà in considerazione il calcolo dell'ora legale.
nathanb,

1
Controlla se mysql conosce correttamente l'ora legale, le regole dell'ora legale vengono aggiornate regolarmente e anche le relative tabelle mysql devono essere aggiornate (vedi sopra in fondo alla mia risposta)
Timo Huovinen,

1

Pro e contro sono praticamente identici, dipende dal fatto che tu lo voglia o no.

Fai attenzione, se il fuso orario di MySQL differisce dall'ora del tuo sistema (ad esempio PHP), il confronto tra il tempo o la stampa con l'utente comporterà alcuni aggiustamenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.