MySQL devrait-il avoir son fuseau horaire réglé sur UTC?

149

Question de suivi de /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

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

Quels sont les avantages et inconvénients?

Timo Huovinen
la source
stackoverflow.com/a/1650406/175071 partage de bonnes raisons d'utiliser UTC
Timo Huovinen
UTC n'est pas un fuseau horaire. UTC est une norme, GMT est un fuseau horaire. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev
Une autre bonne raison d'utiliser UTC dba.stackexchange.com/questions/161416/…
Timo Huovinen

Réponses:

533

Il semble que le fuseau horaire du serveur n'a pas d'importance tant que vous avez l'heure correctement définie pour le fuseau horaire actuel, que vous connaissez le fuseau horaire des colonnes datetime que vous stockez et que vous êtes conscient des problèmes liés à l'heure d'été.

D'un autre côté, si vous contrôlez les fuseaux horaires des serveurs avec lesquels vous travaillez, vous pouvez tout régler sur UTC en interne et ne jamais vous soucier des fuseaux horaires et de l'heure d'été.

Voici quelques notes que j'ai collectées sur la façon de travailler avec les fuseaux horaires comme une forme de feuille de triche pour moi et pour les autres, ce qui pourrait influencer le fuseau horaire que la personne choisira pour son serveur et comment elle stockera la date et l'heure.

Aide-mémoire du fuseau horaire MySQL

Remarques:

  1. La modification du fuseau horaire ne changera pas la date ou l'horodatage stockés , mais sélectionnera une autre date / heure dans les colonnes d'horodatage
  2. Avertissement! UTC a des secondes intercalaires, celles-ci ressemblent à '2012-06-30 23:59:60' et peuvent être ajoutées au hasard, avec un préavis de 6 mois, en raison du ralentissement de la rotation de la Terre
  3. GMT confond les secondes, c'est pourquoi UTC a été inventé.

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

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

    Lors du stockage d'une date dans un horodatage, MySQL supposera que la date est dans le fuseau horaire de la session actuelle et la convertira en UTC pour le stockage.

  7. MySQL peut stocker des dates partielles dans des colonnes datetime, celles-ci ressemblent à "2013-00-00 04:00:00"
  8. MySQL stocke «0000-00-00 00:00:00» si vous définissez une colonne datetime comme NULL, sauf si vous définissez spécifiquement la colonne pour autoriser null lorsque vous la créez.
  9. Lis ça

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

quel que soit le fuseau horaire dans lequel se trouve 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 qui a été défini lors du lancement du serveur

SELECT @@system_time_zone;

Renvoie "MSK" ou "+04: 00" pour l'heure de Moscou, par exemple, il y a (ou était) un bogue MySQL où s'il était défini sur un décalage numérique, il n'ajusterait 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 forme d'horodatage UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Pour obtenir une colonne de date et heure UTC comme 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 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) 

Il y a 3 endroits où le fuseau horaire peut être défini dans MySQL:

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. comme 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'

@@ variable global.time_zone

Pour voir à quelle valeur ils sont définis

SELECT @@global.time_zone;

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

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;

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'ils 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 tables d'informations de fuseau horaire qui doivent être remplies: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. html

Remarque: vous ne pouvez pas faire cela car cela renverra NULL:

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

Configurer les tables de fuseaux horaires MySQL

Pour CONVERT_TZfonctionner, vous avez besoin que les tables de fuseaux horaires soient remplies

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 du fuseau horaire

le correctif étant d'exécuter ceci

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 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Voir l'historique complet des transitions 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 toutes les modifications DST nécessaires en fonction des règles des tableaux ci-dessus et de la date que vous utilisez.

Remarque:
selon la documentation , la valeur que vous définissez pour time_zone ne change pas, si vous la définissez comme "+01: 00" par exemple, alors la zone time_zone sera définie comme un décalage par rapport à UTC, qui ne suit pas l'heure d'été, donc il restera le même toute l'année.

Seuls les fuseaux horaires nommés changeront d'heure pendant l'heure d'été.

Les abréviations comme CETseront toujours une heure d'hiver et CESTseront l'heure d'été tandis que +01: 00 sera toujoursUTC heure + 1 heure et les deux ne changeront pas avec l'heure d'été.

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

Vous pouvez en savoir plus sur l'utilisation de l'heure d'été ici

questions connexes:

Sources:

Timo Huovinen
la source
Donc, si mon type de colonne est défini sur horodatage. Et mon time_zone est +12: 00, et je veux mettre à jour une colonne en utilisant une date / heure basée sur utc, y a-t-il un moyen d'inclure le fuseau horaire dans la déclaration de mise à jour, ou devrais-je utiliser convert_tz. Par exemple. update tableset modified= '2016-07-07 08:10 +00: 00'
bumperbox
2
@bumperbox mysql suppose toujours que la date que vous donnez à la colonne d'horodatage est dans le même fuseau horaire que le serveur mysql, vous devez donc convertir votre date de votre fuseau horaire +12: 00 au fuseau horaire de votre serveur mysql pour la mise à jour. C'est pourquoi j'utilise UTC sur le serveur mysql et je convertis n'importe quelle date en UTC avant de la stocker.
Timo Huovinen le
5
L'une des réponses les meilleures et les plus informatives que j'ai rencontrées depuis des années d'utilisation de SO. Je vous remercie.
Mitya
AVERTISSEMENT!!! Toute utilisation ou conversion de l'heure locale dans un fuseau horaire DST sera erronée d'une heure pendant une heure chaque année à la fin de l'heure d'été. Cela affecte UNIX_TIMESTAMP(NOW());ainsi que toutes vos utilisations CONVERT_TZ()où l'un des paramètres est `@@ session.time_zone. Pour convertir de manière fiable les heures de données UTC en horodatages UNIX, vous devez d'abord définir la zone time_zone de la session.
Fait
1
@Flimm tout à fait raison, j'ai oublié de résoudre ce problème il y a quelque temps.
Timo Huovinen
3

Voici un exemple de travail:

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

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


la source
Il s'agit essentiellement de deux lignes de code: date_default_timezone_set("America/Los_Angeles");et a mysql_query("SET time_zone='" . date('P', time()) . "'");travaillé très élégamment!
Noumenon
3
@Noumenon Attention avec ça! Je me suis gratté la tête ce matin parce que c'est exactement ce que je faisais, et certains de mes temps sont maintenant écoulés d'une heure. Ce que je soupçonne, c'est que l'utilisation d'un fuseau horaire nommé est plus précise lorsque l'heure d'été est impliquée. Si vous utilisez America / New_York, MySQL connaît l'heure d'été et stockera les dates de manière appropriée. Si vous le réglez simplement sur -04: 00 comme vous l'avez fait ici, le calcul de l'heure d'été ne sera pas pris en compte.
nathanb
1
Vérifiez si mysql connaît correctement DST, les règles DST sont régulièrement mises à jour et les tables mysql associées doivent également être mises à jour (voir ci-dessus au bas de ma réponse)
Timo Huovinen
1

Les avantages et les inconvénients sont à peu près identiques, cela dépend si vous le souhaitez ou non.

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

alandarev
la source