Database
 sql >> Baza danych >  >> RDS >> Database

Czym jest problem roku 2038?

Problem roku 2038 (nazywany również błędem Y2K38) odnosi się do problemu, który niektóre systemy komputerowe mogą napotkać, gdy mają do czynienia z czasami po 2038-01-19 03:14:07.

Wiele systemów komputerowych, takich jak systemy Unix i Unix, nie oblicza czasu za pomocą kalendarza gregoriańskiego. Obliczają czas jako liczbę sekund od 1 stycznia 1970 roku. Dlatego w tych systemach czas jest przedstawiany jako duża liczba (tj. liczba sekund, które upłynęły od 1970-01-01 00:00:00). Jest to zwykle określane jako czas epoki, czas uniksowy, czas epoki uniksowej lub czas POSIX. Kiedy to piszę, czas uniksowy to 1560913841. I kiedy piszę następną linię, czas uniksowy wzrósł do 1560913879.

Problem 2038 jest spowodowany faktem, że wiele systemów przechowuje tę liczbę jako 32-bitową binarną liczbę całkowitą ze znakiem. Zakres 32-bitowej liczby całkowitej ze znakiem wynosi od -2 147 483 648 do 2 147 483 647. Oznacza to, że ostatni czas Epoki, który można przedstawić, to 2147483647. Nastąpi to o 03:14:07 we wtorek 19 stycznia 2038 r.

Następnie wynik będzie w dużej mierze zależał od systemu. W wielu systemach wystąpi przepełnienie liczby całkowitej, a późniejsze czasy zostaną zawinięte i będą przechowywane wewnętrznie jako liczba ujemna. Skutek jest taki, że sekundę później, czas zostanie zinterpretowany jako 13 grudnia 1901, a nie 19 stycznia 2038.

Jednak możesz również uzyskać różne wyniki, w zależności od używanej aplikacji. Nawet jeśli twój system operacyjny nie ma problemu, twój własny kod może nadal mieć problem. Na przykład, jeśli napisałeś niestandardowy kod zwracający czas uniksowy i przechowujesz go w podpisanej 4-bajtowej liczbie całkowitej, będziesz mieć problemy. W takich przypadkach przepisanie kodu na 8-bajtową liczbę całkowitą może być wszystkim, co musisz zrobić.

Biorąc pod uwagę, że ta strona internetowa dotyczy baz danych, oto kilka przykładów baz danych.

Przykład 1 – MySQL

W MySQL TIMESTAMP typ danych obsługuje daty/czasy od ‘1970-01-01 00:00:01.000000’ UTC do ‘2038-01-19 03:14:07.999999’. Dlatego można powiedzieć, że każda baza danych korzystająca z tego typu danych ma błąd Y2K38.

MySQL ma również wbudowaną funkcję o nazwie UNIX_TIMESTAMP() który, jak można się spodziewać, zwraca uniksowy znacznik czasu.

UNIX_TIMESTAMP() funkcja przyjmuje opcjonalny argument, który pozwala określić datę, która ma być używana dla czasu uniksowego (tj. liczba sekund od ‘1970-01-01 00:00:00’ UTC do podanego czasu). Prawidłowy zakres wartości argumentów jest taki sam jak dla TIMESTAMP typ danych, od ‘1970-01-01 00:00:01.0000’ UTC do ‘2038-01-19 03:14:07.999999’ UTC. Jeśli przekażesz do tej funkcji datę spoza zakresu, zwróci ona 0 .

Oto, co się stanie, jeśli spróbujesz użyć tej funkcji do zwrócenia czasu uniksowego z daty po „2038-01-19 03:14:07.999999”:

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

Wynik:

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

Otrzymujemy 0 ponieważ argument daty jest poza obsługiwanym zakresem.

Powiązany raport o błędzie został zgłoszony zespołowi MySQL w 2005 roku (chociaż niektóre szczegóły wydają się być inne), a w chwili pisania tego tekstu nadal nie został rozwiązany.

Podobny problem został również podniesiony w celu rozwiązania ograniczeń związanych z TIMESTAMP typ danych, który również nie został jeszcze rozwiązany.

Przykład 2 – Serwer SQL

SQL Server nie ma obecnie odpowiednika UNIX_TIMESTAMP MySQLa funkcjonować. Dlatego, jeśli chcesz zwrócić czas Epoki, musisz zrobić coś takiego:

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

Jest to dobre dla dat sprzed 2038 roku. Po tej dacie będziesz mieć problemy, ponieważ DATEDIFF() funkcja zwraca wynik jako int typ danych. int typ danych ma zakres od -2^31 (-2147483648) do 2^31-1 (2147483647).

Oto co się stanie, jeśli spróbuję zwrócić czas Epoki później niż „2038-01-19 03:14:07”:

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

Wynik:

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 szczęście istnieje również funkcja DATEDIFF_BIG() funkcja, która robi dokładnie to samo, z wyjątkiem tego, że zwraca wynik jako bigint typ danych.

Aby rozwiązać ten problem, możemy przepisać poprzedni przykład na następujący:

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

Wynik:

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

Wielki typ danych używa 8 bajtów (w przeciwieństwie do 4 bajtów dla int ), więc musisz zdecydować, czy przełączyć się na DATEDIFF_BIG() teraz albo później. Jeśli Twoja aplikacja dotyczy przyszłych dat, rozsądne może być zrobienie tego wcześniej niż później.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Instrukcja SQL INSERT INTO

  2. Podstawy wyrażeń tablicowych, Część 6 – Rekurencyjne CTE

  3. N-ta najwyższa pensja

  4. Niespodzianki dotyczące wydajności i założenia:DATADODANO

  5. Model danych ważnych dat