sql >> Databáze >  >> RDS >> Database

Jaký je problém roku 2038?

Problém roku 2038 (také označovaný jako chyba Y2K38) se týká problému, se kterým se mohou některé počítačové systémy setkat při řešení časů minulých 2038-01-19 03:14:07.

Mnoho počítačových systémů, jako je Unix a systémy založené na Unixu, nepočítá čas pomocí gregoriánského kalendáře. Čas počítají jako počet sekund od 1. ledna 1970. Proto je v těchto systémech čas reprezentován velkým číslem (tj. počtem sekund, které uplynuly od 1970-01-01 00:00:00). To se obvykle označuje jako čas epochy, čas Unixu, čas epochy Unix nebo čas POSIX. Když to píšu, čas Unixu je 1560913841. A když píšu tento další řádek, čas Unixu se zvýšil na 1560913879.

Problém 2038 je způsoben skutečností, že mnoho systémů ukládá toto číslo jako 32bitové binární celé číslo se znaménkem. Rozsah 32bitového celého čísla se znaménkem je -2 147 483 648 až 2 147 483 647. To znamená, že poslední čas epochy, který lze znázornit, je 2147483647. K tomu dojde v úterý 19. ledna 2038 v 03:14:07.

Poté bude výsledek do značné míry záviset na systému. V mnoha systémech dojde k přetečení celého čísla a jakékoli pozdější časy se zalomí a budou interně uloženy jako záporné číslo. Výsledkem je, že o jednu sekundu později bude čas interpretován jako 13. prosince 1901, nikoli 19. ledna 2038.

Můžete však také skončit s různými výsledky v závislosti na používané aplikaci. I když váš operační systém nemá žádný problém, váš vlastní kód může mít stále problém. Pokud jste například napsali vlastní kód pro návrat Unixového času a uložíte jej pod 4bajtové celé číslo se znaménkem, budete mít problémy. V takových případech může být vše, co musíte udělat, přepsání kódu na 8bajtové celé číslo.

Vzhledem k tomu, že tento web je o databázích, zde jsou některé příklady databází.

Příklad 1 – MySQL

V MySQL je to TIMESTAMP datový typ podporuje data/časy od ‚1970-01-01 00:00:01.000000‘ UTC do ‚2038-01-19 03:14:07.999999‘. Dalo by se tedy říci, že každá databáze používající tento datový typ má chybu Y2K38.

MySQL má také vestavěnou funkci nazvanou UNIX_TIMESTAMP() který, jak byste mohli očekávat, vrací Unixové časové razítko.

UNIX_TIMESTAMP() funkce přijímá volitelný argument, který vám umožňuje zadat datum, které se má použít pro čas Unix (tj. počet sekund od ‚1970-01-01 00:00:00‘ UTC do vámi zadaného času). Platný rozsah hodnot argumentů je stejný jako u TIMESTAMP datový typ, což je „1970-01-01 00:00:01.000000“ UTC až „2038-01-19 03:14:07.999999“ UTC. Pokud této funkci předáte datum mimo rozsah, vrátí 0 .

Zde je to, co se stane, když se pokusíte použít tuto funkci k vrácení unixového času z data po 2038-01-19 03:14:07.999999:

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

Výsledek:

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

Dostaneme 0 protože argument data je mimo podporovaný rozsah.

V roce 2005 byla pro tým MySQL vznesena související zpráva o chybě (ačkoli některá specifika se zdají být odlišná), a v době psaní tohoto článku stále nebyla vyřešena.

Podobný problém byl také nastolen při řešení omezení s TIMESTAMP datový typ, který také ještě není vyřešen.

Příklad 2 – SQL Server

SQL Server v současné době nemá ekvivalent UNIX_TIMESTAMP MySQL funkce. Pokud tedy potřebujete vrátit čas Epochy, budete muset udělat něco takového:

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

To je v pořádku pro data před problémem v roce 2038. Po tomto datu budete mít problémy, protože DATEDIFF() funkce vrátí výsledek jako int datový typ. int datový typ má rozsah -2^31 (-2,147,483,648) až 2^31-1 (2,147,483,647).

Zde je to, co se stane, když se pokusím vrátit čas epochy později než „2038-01-19 03:14:07“:

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

Výsledek:

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.

Naštěstí existuje také DATEDIFF_BIG() funkce, která dělá přesně to samé, kromě toho, že vrací výsledek jako bigint datový typ.

Takže můžeme přepsat předchozí příklad na následující, abychom tento problém vyřešili:

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

Výsledek:

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

velký datový typ používá 8 bajtů (na rozdíl od 4 bajtů pro int ), takže se budete muset rozhodnout, zda přejít na DATEDIFF_BIG() teď nebo později. Pokud se vaše aplikace zabývá budoucími daty, může být rozumné to udělat dříve než později.


  1. MySQL InnoDB Cluster 8.0 – kompletní průvodce nasazením:část první

  2. Jak duplikovat databázi pomocí phpMyAdmin

  3. Jak opravit ORA-12505, TNS:listener aktuálně neví o SID uvedeném v deskriptoru připojení

  4. Převeďte VARCHAR2 na číslo