Database
 sql >> Base de données >  >> RDS >> Database

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

Le problème de l'année 2038 (également appelé bogue Y2K38) fait référence à un problème que certains systèmes informatiques peuvent rencontrer lorsqu'ils traitent des heures passées le 2038-01-19 03:14:07.

De nombreux systèmes informatiques, tels que les systèmes Unix et basés sur Unix, ne calculent pas le temps à l'aide du calendrier grégorien. Ils calculent le temps comme le nombre de secondes depuis le 1er janvier 1970. Par conséquent, dans ces systèmes, le temps est représenté comme un grand nombre (c'est-à-dire le nombre de secondes écoulées depuis le 1970-01-01 00:00:00). Il s'agit généralement de l'heure Epoch, de l'heure Unix, de l'heure Unix Epoch ou de l'heure POSIX. Au moment où j'écris ceci, l'heure Unix est 1560913841. Et au moment où j'écris cette ligne suivante, l'heure Unix est passée à 1560913879.

Le problème 2038 est dû au fait que de nombreux systèmes stockent ce nombre sous la forme d'un entier binaire 32 bits signé. La plage d'un entier 32 bits signé est de -2 147 483 648 à 2 147 483 647. Cela signifie que la dernière heure Epoch pouvant être représentée est 2147483647. Cela se produira à 03:14:07 le mardi 19 janvier 2038.

Après cela, le résultat dépendra largement du système. Dans de nombreux systèmes, un débordement d'entier se produira, et toutes les heures ultérieures s'enrouleront et seront stockées en interne sous la forme d'un nombre négatif. Le résultat est qu'une seconde plus tard, l'heure sera interprétée comme étant celle du 13 décembre 1901 au lieu du 19 janvier 2038.

Cependant, vous pouvez également obtenir des résultats variables, en fonction de l'application utilisée. Même si votre système d'exploitation n'a pas de problème, votre propre code peut toujours avoir un problème. Par exemple, si vous avez écrit un code personnalisé pour renvoyer l'heure Unix et que vous le stockez dans un entier signé de 4 octets, vous aurez des problèmes. Dans de tels cas, réécrire le code pour utiliser un entier de 8 octets peut être tout ce que vous avez à faire.

Étant donné que ce site Web est entièrement consacré aux bases de données, voici quelques exemples de bases de données.

Exemple 1 – MySQL

Dans MySQL, le TIMESTAMP le type de données prend en charge les dates/heures de '1970-01-01 00:00:01.000000' UTC à '2038-01-19 03:14:07.999999'. Par conséquent, vous pourriez dire que toute base de données utilisant ce type de données a un bogue Y2K38.

MySQL a également une fonction intégrée appelée UNIX_TIMESTAMP() qui, comme vous vous en doutez, renvoie l'horodatage Unix.

Le UNIX_TIMESTAMP() La fonction accepte un argument facultatif qui vous permet de spécifier une date à utiliser pour l'heure Unix (c'est-à-dire le nombre de secondes entre '1970-01-01 00:00:00' UTC et l'heure que vous spécifiez). La plage valide de valeurs d'arguments est la même que pour le TIMESTAMP type de données, qui est ‘1970-01-01 00:00:01.000000’ UTC à ‘2038-01-19 03:14:07.999999’ UTC. Si vous passez une date hors plage à cette fonction, elle renvoie 0 .

Voici ce qui se passe si vous essayez d'utiliser cette fonction pour renvoyer l'heure Unix à partir d'une date postérieure au 19/01/2038 03:14:07.999999 :

SELECT UNIX_TIMESTAMP('2038-01-20') Result;

Résultat :

+--------+
| Result |
+--------+
|      0 |
+--------+

Nous obtenons 0 car l'argument de date est en dehors de la plage prise en charge.

Un rapport de bogue connexe a été soulevé pour l'équipe MySQL en 2005 (bien que certaines des spécificités semblent être différentes), et à ce jour, il n'a toujours pas été traité.

Un problème similaire a également été soulevé pour résoudre les limitations avec le TIMESTAMP type de données, qui n'a pas encore été traité.

Exemple 2 – SQL Server

SQL Server n'a pas actuellement d'équivalent du UNIX_TIMESTAMP de MySQL une fonction. Par conséquent, si vous devez retourner l'heure d'Epoch, vous devrez faire quelque chose comme ceci :

SELECT DATEDIFF(SECOND,'1970-01-01', GETUTCDATE());

C'est bien pour les dates antérieures au problème de 2038. Après cette date, vous aurez des problèmes, car le DATEDIFF() la fonction renvoie le résultat sous la forme d'un int Type de données. Le int le type de données est compris entre -2^31 (-2 147 483 648) et 2^31-1 (2 147 483 647).

Voici ce qui se passe si j'essaie de renvoyer l'heure d'Epoch après '2038-01-19 03:14:07' :

SELECT DATEDIFF(SECOND,'1970-01-01', '2038-01-19 03:14:08') AS 'Result';

Résultat :

The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.

Heureusement, il y a aussi un DATEDIFF_BIG() fonction, qui fait exactement la même chose, sauf qu'elle renvoie le résultat sous la forme d'un bigint type de données.

Nous pouvons donc réécrire l'exemple précédent comme suit pour résoudre ce problème :

SELECT DATEDIFF_BIG(SECOND,'1970-01-01 00:00:00', '2038-01-19 03:14:08') AS 'Result';

Résultat :

+------------+
| Result     |
|------------|
| 2147483648 |
+------------+

Le bigint le type de données utilise 8 octets (par opposition à 4 octets pour un int ), vous devrez donc décider de passer ou non à DATEDIFF_BIG() maintenant ou plus tard. Si votre candidature porte sur des dates futures, il peut être prudent de le faire plus tôt que plus tard.