PHP & mySQL: Année 2038 Bogue: Qu'est-ce que c'est? Comment le résoudre?

116

Je pensais utiliser TIMESTAMP pour stocker la date et l'heure, mais j'ai lu qu'il y avait une limitation de l'année 2038 dessus. Au lieu de poser ma question en gros, j'ai préféré la diviser en petites parties pour qu'elle soit également facile à comprendre pour les utilisateurs novices. Donc ma (mes) question (s):

  1. Quel est exactement le problème de l'an 2038?
  2. Pourquoi cela se produit-il et que se passe-t-il quand cela se produit?
  3. Comment pouvons-nous le résoudre?
  4. Existe-t-il des alternatives possibles à son utilisation, qui ne posent pas un problème similaire?
  5. Que pouvons-nous faire aux applications existantes qui utilisent TIMESTAMP, pour éviter le soi-disant problème, quand il se produit vraiment?

Merci d'avance.

Devner
la source
1
Il reste 28 ans. Utilisez-vous encore une technologie informatique depuis 1982? Improbable. Alors ne vous inquiétez pas, car d'ici 2038, ce ne sera probablement plus un problème.
Gordon le
24
Gordon, je fais une application qui fait des prévisions. J'économise combien d'argent j'ai chaque mois et je peux alors estimer quand je serai millionnaire. Dans mon cas, 28 ans, ce n'est pas tant que ça, et je suis sûr que je ne suis pas le seul à avoir ce problème en ce moment (je l'ai résolu en utilisant des nombres 64 bits pour représenter l'horodatage).
Emil Vikström le
2
@Emil En utilisant des entiers de 64 bits en ce moment , vous vous avez trouvé une solution facile à un problème concret. Non applicable à (ou requis par) tout le monde, mais fonctionne pour votre cas d'utilisation. Le fait est que si l'OP n'a pas de problème concret, comme la prévision, alors cela pourrait être un sujet intéressant, mais il ne devrait pas s'inquiéter, car résoudre cela à un niveau général n'est pas un problème PHP (attention à la balise). Juste mon 2c.
Gordon le
1
D'ici 2038, l'analyse de la chaîne "AAAA-MM-JJ HH: MM: SS: mmmm ..." sera l'opération la moins chère dont vous pouvez rêver. D'ici 2038, 32 bits sera obsolète. Je doute que l'horodatage Unix tel que nous le connaissons existera alors, et si c'est le cas, nos systèmes 256 bits géreront des dates qui vont bien au-delà de l'âge où les systèmes 4096 bits sont distribués dans les repas heureux.
Super Cat
8
Gordon, ses 9 ans plus tard maintenant. Les TIMESTAMPS sont toujours utilisés. Nous utilisons toujours la technologie d'il y a 28 ans. Son appelé le World Wide Web.
sfscs

Réponses:

149

J'ai marqué ceci comme un wiki communautaire, alors n'hésitez pas à le modifier à votre guise.

Quel est exactement le problème de l'an 2038?

"Le problème de l'année 2038 (également connu sous le nom de bogue Unix Millennium, l'an 2000 par analogie avec le problème de l'an 2000) peut entraîner l'échec de certains logiciels avant ou pendant l'année 2038. Le problème affecte tous les logiciels et systèmes qui stockent l'heure système sous la forme d'un 32 -bit integer et interpréter ce nombre comme le nombre de secondes depuis 00:00:00 UTC le 1er janvier 1970. "


Pourquoi cela se produit-il et que se passe-t-il quand cela se produit?

Les heures au-delà de 03:14:07 UTC le mardi 19 janvier 2038 «s'enrouleront» et seront stockées en interne sous la forme d'un nombre négatif, que ces systèmes interpréteront comme une heure du 13 décembre 1901 plutôt qu'en 2038. Cela est dû à le fait que le nombre de secondes depuis l'époque UNIX (1er janvier 1970 00:00:00 GMT) aura dépassé la valeur maximale d'un ordinateur pour un entier signé de 32 bits.


Comment pouvons-nous le résoudre?

  • Utilisez des types de données longs (64 bits suffisent)
  • Pour MySQL (ou MariaDB), si vous n'avez pas besoin des informations de temps, envisagez d'utiliser le DATEtype de colonne. Si vous avez besoin d'une précision plus élevée, utilisez DATETIMEplutôt que TIMESTAMP. Attention, les DATETIMEcolonnes ne stockent pas d'informations sur le fuseau horaire, votre application devra donc savoir quel fuseau horaire a été utilisé.
  • Autres solutions possibles décrites sur Wikipedia
  • Attendez que les développeurs MySQL corrigent ce bogue signalé il y a plus de dix ans.

Existe-t-il des alternatives possibles à son utilisation, qui ne posent pas un problème similaire?

Essayez dans la mesure du possible d'utiliser de grands types pour stocker des dates dans des bases de données: 64 bits suffit - un type long long en GNU C et POSIX / SuS, ou sprintf('%u'...)en PHP ou l'extension BCmath.


Quels sont les cas d'utilisation potentiellement cassants même si nous ne sommes pas encore en 2038?

Ainsi, un DATETIME MySQL a une plage de 1000 à 9 999, mais TIMESTAMP n'a qu'une plage de 1970 à 2038. Si votre système stocke les dates de naissance, les dates futures futures (par exemple, les hypothèques à 30 ans) ou similaire, vous allez déjà rencontrer ce bogue. Encore une fois, n'utilisez pas TIMESTAMP si cela pose un problème.


Que pouvons-nous faire aux applications existantes qui utilisent TIMESTAMP, pour éviter le soi-disant problème, quand il se produit vraiment?

Peu d'applications PHP seront encore disponibles en 2038, bien qu'il soit difficile de prévoir que le Web n'est pas encore une plate-forme héritée.

Voici un processus pour modifier une colonne de table de base de données pour convertir TIMESTAMPà DATETIME. Cela commence par la création d'une colonne temporaire:

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

Ressources

Corey Ballou
la source
2
Impressionnant. Pour moi, votre réponse est la plus complète. Merci beaucoup.
Devner
7
Dans MySQL, si la version future change le type de données de stockage sous-jacent de TIMESTAMP en 64 bits, il n'est pas nécessaire de changer votre code en DATETIME, n'est-ce pas? Je ne pense tout simplement pas que décourager quiconque d'utiliser TIMESTAMP est la bonne chose à faire, car ce type de données a son but.
pixelfreak
1
Le champ BIGINT signé de MySQL semble fonctionner correctement pour stocker les horodatages et j'ai fait des tests locaux sur MySQL 5.5, ce qui confirme que cela fonctionne. De toute évidence, utiliser signé serait mieux que non signé car vous pouvez également représenter des dates dans le passé. Une raison de ne pas utiliser BIGINT pour les horodatages?
zuallauz
Une chose à noter, MySQL n'a qu'un réglage automatique de la date / heure actuelle (CURRENT_TIMESTAMP) pour les champs d'horodatage. Espérons que cette fonctionnalité sera éventuellement portée sur tous les types de dates.
Ray
5
Il est absolument absurde que MySQL (et MariaDB) n'utilise pas d'entiers 64 bits pour stocker les horodatages sur les systèmes 64 bits. L'utilisation de DATETIME n'est pas une solution adéquate car nous n'avons aucune idée du fuseau horaire. Cela a été signalé en 2005 , mais aucun correctif n'est disponible.
Mike
14

Lorsque vous utilisez des horodatages UNIX pour stocker des dates, vous utilisez en fait un nombre entier de 32 bits, qui tient compte du nombre de secondes depuis le 01/01/1970; voir l' heure Unix

Ce nombre de 32 bits débordera en 2038. C'est le problème de 2038.


Pour résoudre ce problème, vous ne devez pas utiliser un horodatage UNIX 32 bits pour stocker vos dates - ce qui signifie que lorsque vous utilisez MySQL, vous ne devez pas utiliser TIMESTAMP, mais DATETIME(voir 10.3.1. Les types DATETIME, DATE et TIMESTAMP ):

Le DATETIMEtype est utilisé lorsque vous avez besoin de valeurs contenant à la fois des informations de date et d'heure. La plage prise en charge est '1000-01-01 00:00:00'de '9999-12-31 23:59:59'.

Le TIMESTAMPtype de données a une plage de '1970-01-01 00:00:01'UTC à '2038-01-19 03:14:07'UTC.


La meilleure chose (probablement) que vous puissiez faire à votre application pour éviter / résoudre ce problème est de ne pas utiliser TIMESTAMP, mais DATETIMEpour les colonnes qui doivent contenir des dates qui ne sont pas comprises entre 1970 et 2038.

Une petite note, cependant: il y a une très grande probabilité (statistiquement parlant) que votre candidature ait été réécrite plusieurs fois avant 2038 ^^ Alors peut-être, si vous n'avez pas à vous occuper de dates dans le futur , vous n'aurez pas à vous occuper de ce problème avec la version actuelle de votre application ...

Pascal MARTIN
la source
1
+1 Pour l'info. La tentative ici est d'adapter les meilleures pratiques dès le départ afin de ne pas avoir à s'inquiéter du problème plus tard. Donc, même si pour l'instant 2038 ne semble pas être un problème, je veux simplement suivre les meilleures pratiques et les suivre pour chaque application que je crée, dès le début. J'espère que cela a du sens.
Devner
Oui, cela a du sens, je comprends votre point de vue. Mais «meilleure pratique» peut aussi signifier «ce qui répond au besoin» - Si vous savez qu'un horodatage suffira, il n'est pas nécessaire d'utiliser un datetime (ceux-ci ont besoin de plus de mémoire pour être stockés, par exemple; et cela peut avoir de l'importance si vous avez des millions d'enregistrements) ;; J'ai des applications dans lesquelles j'utilise l'horodatage pour certaines colonnes (colonnes qui contiennent la date actuelle, par exemple), et datetime pour d'autres (colonnes qui contiennent des dates passées / futures, par exemple)
Pascal MARTIN
Je vois que votre procédure a également du sens et fonctionne bien, surtout en ce qui concerne l'espace de stockage. Si tout va bien, puis-je vous demander quelle structure et quelle longueur vous utilisez généralement pour la colonne TIMESTAMP dans vos applications? Merci.
Devner
Eh bien, quand je veux utiliser un TIMESTAMP, c'est pour / parce que mes données "date / heure" correspondent entre 1970 et 2038 - et, donc, j'utilise le type de données MySQL TIMESTAMP.
Pascal MARTIN
Merci pour l'info. D'après votre réponse, je comprends qu'il suffit de déclarer la colonne comme TIMESTAMP et que nous n'avons pas besoin de lui fournir de longueur (contrairement à et int ou var, où nous fournissons la longueur). Ai-je raison?
Devner
7

Une recherche rapide sur Google fera l'affaire: problème de l'année 2038

  1. Le problème de l'année 2038 (également connu sous le nom de bogue Unix Millennium, Y2K38 par analogie avec le problème de l'an 2000) peut provoquer l'échec de certains logiciels avant ou pendant l'année 2038.
  2. Le problème affecte tous les logiciels et systèmes qui stockent l'heure système sous la forme d'un entier 32 bits signé et interprètent ce nombre comme le nombre de secondes depuis 00:00:00 UTC le 1er janvier 1970. La dernière heure qui peut être représentée de cette façon est 03:14:07 UTC le mardi 19 janvier 2038. Les heures au-delà de ce moment "s'enrouleront" et seront stockées en interne sous la forme d'un nombre négatif, que ces systèmes interpréteront comme une date en 1901 plutôt qu'en 2038
  3. Il n'y a pas de solution facile à ce problème pour les combinaisons CPU / OS existantes, les systèmes de fichiers existants ou les formats de données binaires existants
Rubens Farias
la source
2

http://en.wikipedia.org/wiki/Year_2038_problem contient la plupart des détails

En résumé:

1) + 2) Le problème est que de nombreux systèmes stockent les informations de date sous la forme d'un entier signé 32 bits égal au nombre de secondes depuis le 1/1/1970. La dernière date qui peut être stockée de cette manière est 03:14:07 UTC le mardi 19 janvier 2038. Lorsque cela se produit, l'int "s'enroule" et est stocké comme un nombre négatif qui sera interprété comme une date en 1901. Ce qui se passera alors exactement varie d'un système à l'autre, mais il suffit de dire que ce ne sera probablement pas bon pour aucun d'entre eux!

Pour les systèmes qui ne stockent que des dates dans le passé, alors je suppose que vous n'avez pas à vous inquiéter pendant un moment! Le principal problème est avec les systèmes qui fonctionnent avec des dates dans le futur. Si votre système doit fonctionner avec des dates de 28 ans dans le futur, vous devriez commencer à vous inquiéter maintenant!

3) Utilisez l'un des formats de date alternatifs disponibles ou passez à un système 64 bits et utilisez des entiers 64 bits. Ou pour les bases de données, utilisez un autre format d'horodatage (par exemple pour MySQL, utilisez DATETIME)

4) Voir 3!

5) Voir 4 !!! ;)

Addsy
la source
Vos points 4 et 5 me rappellent «Appel par référence». Cela a mis un sourire sur mon visage. Merci et +1 pour la même chose.
Devner
1

Bros, si vous avez besoin d'utiliser PHP pour afficher les horodatages, c'est la MEILLEURE solution PHP sans changer du format UNIX_TIMESTAMP.

Utilisez une fonction custom_date (). À l'intérieur, utilisez le DateTime. Voici la solution DateTime .

Tant que vous avez UNSIGNED BIGINT (8) comme horodatage dans la base de données. Tant que vous avez PHP 5.2.0 ++

Dexter
la source
-1

Comme je ne voulais rien mettre à jour, j'ai demandé à mon backend (MSSQL) de faire ce travail au lieu de PHP!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

Ce n'est peut-être pas un moyen efficace, mais cela fonctionne.

Venkatesh GS Rao
la source