web-dev-qa-db-fra.com

Le fuseau horaire de MySQL doit-il être défini sur UTC?

Question de suivi de https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc

Le fuseau horaire MySQL doit-il être défini sur UTC ou sur le même fuseau horaire que le serveur ou PHP est-il défini? (Si ce n'est pas UTC)

Quels sont les avantages et inconvénients?

132
Timo Huovinen

Il semble que le fuseau horaire sur le serveur importe peu tant que le fuseau horaire actuel est correct, que vous connaissez le fuseau horaire des colonnes datetime que vous stockez et que vous connaissez les problèmes liés à l’heure avancée.

D'autre part, si vous avez le contrôle des fuseaux horaires des serveurs avec lesquels vous travaillez, vous pouvez définir tout le contenu en UTC en interne et ne plus vous soucier des fuseaux horaires ni de l'heure d'été.

Voici quelques notes que j'ai rassemblées sur la façon de travailler avec les fuseaux horaires comme une feuille de triche pour moi-même et d'autres personnes susceptibles d'influencer le fuseau horaire que la personne choisira pour son serveur et la façon dont il/elle enregistrera la date et l'heure.

MySQL Timezone Cheatsheet

Remarques:

  1. Changer le fuseau horaire ne changera pas la date/heure stockée ni l'horodatage , mais sélectionnera une date/heure différente des colonnes timestamp
  2. Attention! UTC a des secondes intercalaires, elles ressemblent à "2012-06-30 23:59:60" et peuvent être ajoutées au hasard, 6 mois avant remarquez, en raison du ralentissement de la rotation de la terre
  3. GMT confond les secondes, raison pour laquelle UTC a été inventé.

  4. Attention! différents fuseaux horaires régionaux peuvent produire la même valeur datetime en raison de l'heure d'été

  5. La colonne timestamp ne prend en charge que les dates 1970-01-01 00:00:01 à 2038-01-19 03:14:07 UTC, en raison de limitation .
  6. En interne, un colonne d'horodatage MySQL est stocké sous la forme UTC mais lors de la sélection d'une date, MySQL le convertit automatiquement dans le fuseau horaire de la session en cours.

    Lorsque vous stockez une date dans un horodatage, MySQL considère que la date est dans le fuseau horaire de la session en cours et le convertit au format UTC pour le stockage.

  7. MySQL peut stocker des dates partielles dans des colonnes datetime, qui ressemblent à "2013-00-00 04:00:00".
  8. MySQL stocke "0000-00-00 00:00:00" si vous définissez une colonne datetime avec la valeur NULL, sauf si vous définissez spécifiquement cette colonne pour autoriser la valeur null lors de sa création.
  9. Lire ceci

Pour sélectionner une colonne d'horodatage au format UTC

quel que soit le fuseau horaire de la session MySQL actuelle:

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

Vous pouvez également définir le fuseau horaire du serveur ou de la session globale ou actuelle sur UTC, puis sélectionner l’horodatage comme suit:

SELECT `timestamp_field` FROM `table_name`

Pour sélectionner la date/heure actuelle en UTC:

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

Exemple de résultat: 2015-03-24 17:02:41

Pour sélectionner la date/heure actuelle dans le fuseau horaire de la session

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

Pour sélectionner le fuseau horaire défini lors du lancement du serveur

SELECT @@system_time_zone;

Retourne "MSK" ou "+04: 00" pour l'heure de Moscou par exemple, il y a (ou était) un bogue MySQL dans lequel, s'il était défini sur un décalage numérique, il ne modifierait pas l'heure d'été.

Pour obtenir le fuseau horaire actuel

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Il retournera 02:00:00 si votre fuseau horaire est +2: 00.

Pour obtenir l'horodatage UNIX actuel (en secondes):

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

Pour obtenir la colonne d'horodatage sous la forme d'un horodatage UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Pour obtenir une colonne datetime UTC sous la forme d'un horodatage UNIX

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

Obtenir une date/heure de fuseau horaire actuel à partir d'un entier d'horodatage UNIX positif

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Obtenir une date/heure UTC à partir d'un horodatage UNIX

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

Obtenir une date/heure de fuseau horaire actuel à partir d'un entier d'horodatage UNIX négatif

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

Le fuseau horaire peut être défini dans MySQL à trois endroits:

Remarque: Un fuseau horaire peut être défini dans 2 formats:

  1. un décalage par rapport à UTC: '+00: 00', '+10: 00' ou '-6: 00'
  2. en tant que fuseau horaire nommé: 'Europe/Helsinki', 'US/Eastern' ou 'MET'

Les fuseaux horaires nommés ne peuvent être utilisés que si les tables d'informations sur les fuseaux horaires de la base de données mysql ont été créées et remplies.

dans le fichier "my.cnf"

default_time_zone='+00:00'

ou

timezone='UTC'

@@ global.time_zone variable

Pour voir quelle valeur ils sont mis à

SELECT @@global.time_zone;

Pour définir une valeur, utilisez l’un des deux suivants:

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

@@ variable_session.time_zone

SELECT @@session.time_zone;

Pour le définir, utilisez l'un ou l'autre:

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

"@@ global.time_zone variable" et "@@ session.time_zone variable" peuvent renvoyer "SYSTEM", ce qui signifie qu'elles utilisent le fuseau horaire défini dans "my.cnf".

Pour que les noms de fuseau horaire fonctionnent (même pour le fuseau horaire par défaut), vous devez configurer vos tableaux d'informations de fuseau horaire: http: //dev.mysql.com/doc/refman/5.1/en/time-zone-support.html

Note: vous ne pouvez pas faire ceci car cela retournera NULL:

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

Configurer les tables de fuseau horaire mysql

Pour que CONVERT_TZ fonctionne, vous devez renseigner les tables de fuseaux horaires.

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

S'ils sont vides, remplissez-les en exécutant cette commande

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

si cette commande vous donne l'erreur " données trop longues pour la colonne 'abréviation' à la ligne 1 ", cela peut être dû à l'ajout d'un caractère NULL à la fin de l'abréviation de fuseau horaire

le correctif étant d'exécuter cette

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

(assurez-vous que les règles dst de vos serveurs sont à jour zdump -v Europe/Moscow | grep 2011https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Voir l'historique complet de la transition DST (Daylight Saving Time) pour chaque fuseau horaire

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 applique également les modifications de l'heure d'été nécessaires en fonction des règles des tableaux ci-dessus et de la date d'utilisation.

Remarque:
Selon docs , la valeur que vous définissez pour time_zone ne change pas. Si vous le définissez par exemple "+01: 00", le time_zone sera défini comme un décalage. de l’heure UTC, qui ne suit pas l’heure d’été, il restera donc le même toute l’année.

Seul le nom fuseaux horaires changera l'heure pendant l'heure avancée.

Les abréviations telles que CET seront toujours une heure d'hiver et CEST sera une heure d'été, tandis que +01: 00 sera toujours UTC heure + 1 heure et que les deux ne changeront pas avec l'heure d'été.

Le fuseau horaire system sera le fuseau horaire de la machine hôte sur laquelle mysql est installé (sauf si mysql ne parvient pas à le déterminer)

Vous pouvez en savoir plus sur le travail avec DST here

questions connexes:

Sources:

479
Timo Huovinen

Ceci est un exemple de travail:

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

PHP et MySQL ont leurs propres configurations de fuseau horaire par défaut. Vous devez synchroniser l'heure entre votre base de données et votre application Web, sinon vous pourriez rencontrer des problèmes.

Lisez ce tutoriel: Comment synchroniser vos fuseaux horaires PHP et MySQL

2
user1202826

Les avantages et les inconvénients sont quasiment identiques. Cela dépend si vous le souhaitez ou non.

Attention, si le fuseau horaire MySQL diffère de l'heure de votre système (par exemple, PHP), comparer l'heure ou imprimer avec l'utilisateur impliquera du bricolage.

1
alandarev