Sollte die Zeitzone von MySQL auf UTC eingestellt sein?

149

Folgefrage von /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

Sollte die MySQL-Zeitzone auf UTC eingestellt sein oder sollte sie auf dieselbe Zeitzone eingestellt sein wie der Server oder PHP? (Wenn es nicht UTC ist)

Was sind die Vor- und Nachteile?

Timo Huovinen
quelle
stackoverflow.com/a/1650406/175071 teilt gute Gründe für die Verwendung von UTC
Timo Huovinen
UTC ist keine Zeitzone. UTC ist ein Standard, GMT ist eine Zeitzone. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev
Ein weiterer guter
Timo Huovinen vor

Antworten:

532

Es scheint, dass es keine Rolle spielt, welche Zeitzone sich auf dem Server befindet, solange Sie die richtige Zeit für die aktuelle Zeitzone eingestellt haben, die Zeitzone der von Ihnen gespeicherten Datums- / Uhrzeitspalten kennen und sich der Probleme mit der Sommerzeit bewusst sind.

Wenn Sie jedoch die Zeitzonen der Server steuern, mit denen Sie arbeiten, können Sie alles intern auf UTC einstellen und müssen sich keine Gedanken über Zeitzonen und Sommerzeit machen.

Hier sind einige Notizen, die ich gesammelt habe, wie man mit Zeitzonen als eine Art Spickzettel für mich und andere arbeitet, die Einfluss darauf haben können, welche Zeitzone die Person für ihren Server wählt und wie sie Datum und Uhrzeit speichert.

MySQL Timezone Cheatsheet

Anmerkungen:

  1. Durch Ändern der Zeitzone wird die gespeicherte Uhrzeit oder der gespeicherte Zeitstempel nicht geändert , es wird jedoch eine andere Datums- und Uhrzeitangabe aus den Zeitstempelspalten ausgewählt
  2. Warnung! UTC hat Schaltsekunden, diese sehen aus wie '2012-06-30 23:59:60' und können aufgrund der Verlangsamung der Erdrotation mit einer Frist von 6 Monaten nach dem Zufallsprinzip hinzugefügt werden
  3. GMT verwirrt Sekunden, weshalb UTC erfunden wurde.

  4. Warnung! Verschiedene regionale Zeitzonen können aufgrund der Sommerzeit denselben Datums- / Uhrzeitwert erzeugen

  5. Die Zeitstempelspalte unterstützt aufgrund einer Einschränkung nur die Daten 1970-01-01 00:00:01 bis 2038-01-19 03:14:07 UTC .
  6. Intern wird eine MySQL-Zeitstempelspalte als UTC gespeichert. Bei Auswahl eines Datums konvertiert MySQL diese jedoch automatisch in die aktuelle Sitzungszeitzone.

    Beim Speichern eines Datums in einem Zeitstempel geht MySQL davon aus, dass sich das Datum in der aktuellen Sitzungszeitzone befindet, und konvertiert es zur Speicherung in UTC.

  7. MySQL kann Teildaten in Datums- / Uhrzeitspalten speichern. Diese sehen aus wie "2013-00-00 04:00:00".
  8. MySQL speichert "0000-00-00 00:00:00", wenn Sie eine Datums- / Uhrzeitspalte als NULL festlegen, es sei denn, Sie legen die Spalte beim Erstellen ausdrücklich auf Null fest.
  9. Lesen Sie dies

Auswählen einer Zeitstempelspalte im UTC-Format

Egal in welcher Zeitzone sich die aktuelle MySQL-Sitzung befindet:

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

Sie können auch den Server oder die globale oder aktuelle Sitzungszeitzone auf UTC setzen und dann den Zeitstempel wie folgt auswählen:

SELECT `timestamp_field` FROM `table_name`

So wählen Sie die aktuelle Datums- und Uhrzeitangabe in UTC aus:

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

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

Auswählen der aktuellen Datums- und Uhrzeitangabe in der Sitzungszeitzone

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

Auswählen der Zeitzone, die beim Start des Servers festgelegt wurde

SELECT @@system_time_zone;

Gibt "MSK" oder "+04: 00" für die Moskauer Zeit zurück. Es gibt (oder gab) beispielsweise einen MySQL-Fehler, bei dem die Sommerzeit nicht angepasst wird, wenn ein numerischer Versatz eingestellt wird

Um die aktuelle Zeitzone abzurufen

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Es wird 02:00:00 zurückgegeben, wenn Ihre Zeitzone +2: 00 ist.

So erhalten Sie den aktuellen UNIX-Zeitstempel (in Sekunden):

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

So rufen Sie die Zeitstempelspalte als UNIX-Zeitstempel ab

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

So rufen Sie eine UTC-Datums- / Uhrzeitspalte als UNIX-Zeitstempel ab

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

Ruft eine aktuelle Zeitzone datetime von einer positiven UNIX-Zeitstempel-Ganzzahl ab

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Ruft eine UTC-Datumszeit aus einem UNIX-Zeitstempel ab

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

Ruft eine aktuelle Zeitzone datetime von einer negativen UNIX-Zeitstempel-Ganzzahl ab

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

Es gibt 3 Stellen, an denen die Zeitzone in MySQL festgelegt werden kann:

Hinweis: Eine Zeitzone kann in zwei Formaten eingestellt werden:

  1. ein Versatz von UTC: '+00: 00', '+10: 00' oder '-6: 00'
  2. als benannte Zeitzone: "Europa / Helsinki", "USA / Ost" oder "MET"

Benannte Zeitzonen können nur verwendet werden, wenn die Zeitzoneninformationstabellen in der MySQL-Datenbank erstellt und ausgefüllt wurden.

in der Datei "my.cnf"

default_time_zone='+00:00'

oder

timezone='UTC'

@@ global.time_zone Variable

Um zu sehen, auf welchen Wert sie eingestellt sind

SELECT @@global.time_zone;

Verwenden Sie einen der folgenden Werte, um einen Wert festzulegen:

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

@@ session.time_zone Variable

SELECT @@session.time_zone;

Um es einzustellen, verwenden Sie eine der folgenden Optionen:

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

Sowohl "@@ global.time_zone variable" als auch "@@ session.time_zone variable" geben möglicherweise "SYSTEM" zurück, was bedeutet, dass sie die in "my.cnf" festgelegte Zeitzone verwenden.

Damit Zeitzonennamen funktionieren (auch für die Standardzeitzone), müssen Sie Ihre Zeitzoneninformationstabellen einrichten, die ausgefüllt werden müssen: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. html

Hinweis: Sie können dies nicht tun, da NULL zurückgegeben wird:

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

Richten Sie MySQL-Zeitzonentabellen ein

Damit Sie CONVERT_TZarbeiten können, müssen die Zeitzonentabellen ausgefüllt sein

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

Wenn sie leer sind, füllen Sie sie mit diesem Befehl aus

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

Wenn dieser Befehl den Fehler " Daten zu lang für Spalte 'Abkürzung' in Zeile 1 " anzeigt, kann dies daran liegen, dass am Ende der Zeitzonenabkürzung ein NULL-Zeichen angehängt wird

Die Lösung besteht darin, dies auszuführen

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

(Stellen Sie sicher, dass die dst-Regeln Ihres Servers auf dem neuesten Stand sind. zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Den vollständigen DST-Übergangsverlauf (Daylight Saving Time) für jede Zeitzone anzeigen

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 Wendet auch alle erforderlichen DST-Änderungen an, die auf den Regeln in den obigen Tabellen und dem von Ihnen verwendeten Datum basieren.

Hinweis:
Gemäß den Dokumenten ändert sich der Wert, den Sie für time_zone festgelegt haben, nicht. Wenn Sie ihn beispielsweise als "+01: 00" festlegen, wird die time_zone als Versatz von UTC festgelegt, der nicht der Sommerzeit folgt es wird das ganze Jahr über gleich bleiben.

Nur die genannten Zeitzonen ändern die Zeit während der Sommerzeit.

Abkürzungen wie CETwerden immer eine Winterzeit und CESTSommerzeit sein, während +01: 00 immer UTCZeit + 1 Stunde ist und beide sich mit der Sommerzeit nicht ändern.

Die systemZeitzone ist die Zeitzone des Host-Computers, auf dem MySQL installiert ist (es sei denn, MySQL kann dies nicht ermitteln).

Weitere Informationen zur Arbeit mit der Sommerzeit finden Sie hier

verwandte Fragen:

Quellen:

Timo Huovinen
quelle
Wenn ich also meinen Spaltentyp auf Zeitstempel gesetzt habe. Und meine Zeitzone ist +12: 00, und ich möchte eine Spalte mit einem utc-basierten Datum / Uhrzeit aktualisieren. Gibt es eine Möglichkeit, die Zeitzone in die Update-Anweisung aufzunehmen, oder sollte ich convert_tz verwenden? Z.B. update tableset modified= '2016-07-07 08:10 +00: 00'
Stoßstange
2
@bumperbox mysql geht immer davon aus, dass das Datum, an dem Sie die Zeitstempelspalte angeben, in derselben Zeitzone wie der MySQL-Server liegt. Daher müssen Sie Ihr Datum für das Update von Ihrer Zeitzone +12: 00 in Ihre Zeitzone für MySQL-Server konvertieren. Aus diesem Grund verwende ich UTC auf dem MySQL-Server und konvertiere jedes Datum in UTC, bevor ich es speichere.
Timo Huovinen
5
Eine der besten und informativsten Antworten, die ich seit Jahren mit SO gefunden habe. Danke dir.
Mitya
WARNUNG!!! Jede Verwendung oder Umrechnung der Ortszeit in einer DST-Zeitzone ist am Ende der Sommerzeit jedes Jahr um eine Stunde für eine Stunde falsch. Dies betrifft UNIX_TIMESTAMP(NOW());ebenso wie alle Ihre Verwendungen, bei CONVERT_TZ()denen einer der Parameter `@@ session.time_zone ist. Um UTC-Datenzeiten zuverlässig in UNIX-Zeitstempel zu konvertieren, müssen Sie zunächst die Sitzungszeitzone festlegen.
Doin
1
@Flimm ganz richtig, ich habe vor einiger Zeit vergessen, das zu beheben.
Timo Huovinen
3

Dies ist ein funktionierendes Beispiel:

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

PHP und MySQL haben ihre eigenen Standard-Zeitzonenkonfigurationen. Sie sollten die Zeit zwischen Ihrer Datenbank und der Webanwendung synchronisieren, da sonst einige Probleme auftreten können.

Lesen Sie dieses Tutorial: So synchronisieren Sie Ihre PHP- und MySQL-Zeitzonen


quelle
Es sind im Grunde zwei Codezeilen: date_default_timezone_set("America/Los_Angeles");und mysql_query("SET time_zone='" . date('P', time()) . "'");sehr elegant gearbeitet!
Noumenon
3
@ Noumenon Vorsicht damit! Ich habe mir heute Morgen am Kopf gekratzt, weil ich genau das getan habe und einige meiner Zeiten jetzt um eine Stunde verschoben sind. Was ich vermute ist, dass die Verwendung einer benannten Zeitzone genauer ist, wenn DST beteiligt ist. Wenn Sie America / New_York verwenden, kennt MySQL die Sommerzeit und speichert die Daten entsprechend. Wenn Sie es wie hier nur auf -04: 00 einstellen, wird die Sommerzeitberechnung nicht berücksichtigt.
Nathanb
1
Überprüfen Sie, ob MySQL die Sommerzeit richtig kennt, die Sommerzeitregeln regelmäßig aktualisiert werden und die zugehörigen MySQL-Tabellen ebenfalls aktualisiert werden müssen (siehe oben am Ende meiner Antwort)
Timo Huovinen
1

Die Vor- und Nachteile sind ziemlich identisch. Es hängt davon ab, ob Sie dies wollen oder nicht.

Seien Sie vorsichtig, wenn sich die MySQL-Zeitzone von Ihrer Systemzeit unterscheidet (z. B. PHP). Wenn Sie die Zeit vergleichen oder mit dem Benutzer drucken, müssen Sie etwas basteln.

alandarev
quelle