Проблема 2038 года ( также известная как Y2038 , [1] Y2K38 , Y2K38 superbug или Эпохалипс [2] [3] ) — это проблема вычисления времени , из-за которой некоторые компьютерные системы не могут представлять время после 03:14:07 UTC 19 числа. Январь 2038 года.
Проблема существует в системах, которые измеряют время Unix — количество секунд, прошедших с эпохи Unix (00:00:00 UTC 1 января 1970 года) — и сохраняют его в виде 32-битного целого числа со знаком . Тип данных может представлять только целые числа от −(2 31 ) до 2 31 − 1 , что означает, что последнее время, которое может быть правильно закодировано, составляет 2 31 − 1 секунда после эпохи (03:14:07 UTC 19 января 2038 г.). . Попытка увеличения до следующей секунды (03:14:08) приведет к переполнению целого числа , установив для него значение −(2 31 ), которое системы будут интерпретировать как 2 31 секунду до начала эпохи (20:45:52 UTC 13 декабря). 1901). Проблема по своей природе аналогична проблеме 2000 года . Аналогичные ограничения хранения для беззнаковых 32-битных целых чисел будут достигнуты в 2106 году .
Компьютерные системы, использующие время для критических вычислений, могут столкнуться с фатальными ошибками, если не решить проблему 2038 года. Некоторые приложения, использующие будущие даты, уже столкнулись с этой ошибкой. [4] [5] Наиболее уязвимыми системами являются те, которые обновляются нечасто или никогда не обновляются, например устаревшие и встроенные системы . Чтобы решить эту проблему, многие современные системы были модернизированы и теперь измеряют время Unix с помощью 64-битных целых чисел со знаком, для переполнения которых потребуется 292 миллиарда лет, что примерно в 21 раз превышает предполагаемый возраст Вселенной .
Многие компьютерные системы измеряют время и дату как время Unix , международный стандарт цифрового хронометража. Время Unix определяется как количество секунд, прошедших с 00:00:00 UTC 1 января 1970 года (произвольно выбранное время, основанное на создании первой системы Unix ), которое было названо эпохой Unix . [6]
Время в Unix исторически кодировалось как 32-битное целое число со знаком , тип данных, состоящий из 32 двоичных цифр (битов), которые представляют целочисленное значение, причем «знак» означает, что число может представлять как положительные, так и отрицательные числа, а также нуль; и обычно хранится в формате дополнения до двух . [a] Таким образом, 32-битное целое число со знаком может представлять только целочисленные значения от −(2 31 ) до 2 31 − 1 включительно. Следовательно, если для хранения времени Unix используется 32-битное целое число со знаком, самое позднее время, которое может быть сохранено, составляет 2 31 - 1 (2 147 483 647) секунд после эпохи, то есть 03:14:07 во вторник, 19 января 2038 года . 7] Системы, которые пытаются увеличить это значение еще на одну секунду до 2 31 секунды после эпохи (03:14:08), будут страдать от целочисленного переполнения , непреднамеренно меняя знаковый бит, чтобы указать отрицательное число. Это изменит целочисленное значение на −(2 31 ), или 2 31 секунду до начала эпохи, а не после , что системы будут интерпретировать как 20:45:52 в пятницу, 13 декабря 1901 года. Отсюда системы продолжат отсчет в сторону увеличения. ноль, а затем снова вверх по положительным целым числам. Поскольку многие компьютерные системы используют вычисления времени для выполнения критически важных функций, эта ошибка может привести к фатальным ошибкам.
Любая система, использующая структуры данных со знаковыми 32-битными представлениями времени, неизбежно рискует выйти из строя. Полный список этих структур данных получить практически невозможно, но существуют хорошо известные структуры данных, которые имеют проблему времени Unix:
UNIX_TIMESTAMP()
-подобные команды.Проблема Y2038, скорее всего, повлияет на встраиваемые системы , использующие даты для вычислений или диагностики. [1] Несмотря на современное 18–24-месячное обновление технологий компьютерных систем , встроенные системы рассчитаны на срок службы машины, компонентом которой они являются. Вполне возможно, что некоторые из этих систем все еще будут использоваться в 2038 году. Обновление программного обеспечения, на котором работают эти системы, может быть непрактичным, а в некоторых случаях невозможным, что в конечном итоге потребует замены, если необходимо исправить 32-битные ограничения.
Многие транспортные системы, от самолетов до автомобилей, широко используют встроенные системы. В автомобильных системах это может включать антиблокировочную систему тормозов (ABS), электронную систему контроля устойчивости (ESC/ESP), антипробуксовочную систему (TCS) и автоматический полный привод ; самолеты могут использовать инерциальные системы наведения и приемники GPS . [b] Еще одним важным применением встроенных систем являются устройства связи, включая сотовые телефоны и устройства с поддержкой Интернета (например, маршрутизаторы , точки беспроводного доступа , IP-камеры ), которые полагаются на сохранение точного времени и даты и все чаще основаны на Unix-подобных системах. операционные системы. Например, из-за проблемы Y2038 некоторые устройства под управлением 32-битной версии Android аварийно завершают работу и не перезагружаются при изменении времени на эту дату. [8]
Однако это не означает, что все встроенные системы пострадают от проблемы Y2038, поскольку многие такие системы не требуют доступа к датам. Для тех, кто это сделает, те системы, которые отслеживают только разницу между временем/датами, а не абсолютными временем/датами, по природе вычислений не будут испытывать серьезных проблем. Это относится к автомобильной диагностике, основанной на установленных законом стандартах, таких как CARB ( Калифорнийский совет по воздушным ресурсам ). [9]
В мае 2006 года появились сообщения о раннем проявлении проблемы Y2038 в программном обеспечении AOLserver . Программное обеспечение было разработано с учетом особенностей обработки запросов к базе данных, время ожидания которых «никогда» не должно истекать. Вместо того, чтобы специально обрабатывать этот особый случай, первоначальный проект просто задавал произвольную дату тайм-аута в будущем. В конфигурации сервера по умолчанию указано, что время ожидания запроса должно истекать через один миллиард секунд. Один миллиард секунд (приблизительно 32 года) после 01:27:28 UTC 13 мая 2006 года выходит за пределы конечной даты 2038 года. Таким образом, по истечении этого времени расчет тайм-аута переполнился и вернул дату, которая на самом деле была в прошлом, что привело к сбою программного обеспечения. Когда проблема была обнаружена, операторам AOLServer пришлось отредактировать файл конфигурации и установить меньшее значение тайм-аута. [4] [5]
Универсального решения проблемы 2038 года не существует. Например, в языке C любое изменение определения типа time_t
данных приведет к проблемам совместимости кода в любом приложении, в котором представления даты и времени зависят от природы подписанного 32-битного time_t
целого числа. Например, переход time_t
на 32-битное целое число без знака, что расширит диапазон до 2106 [10] (в частности, 06:28:15 UTC в воскресенье, 7 февраля 2106 г.), отрицательно повлияет на программы, которые хранят, извлекают или манипулируют даты до 1970 года, поскольку такие даты представлены отрицательными числами. Увеличение размера типа time_t
до 64 бит в существующей системе привело бы к несовместимым изменениям в расположении структур и двоичном интерфейсе функций.
Большинство операционных систем, предназначенных для работы на 64-битном оборудовании, уже используют 64-битные time_t
целые числа со знаком. Использование 64-битного значения со знаком вводит новую дату цикла, которая более чем в двадцать раз превышает предполагаемый возраст Вселенной : примерно через 292 миллиарда лет. [11] Возможность производить вычисления по датам ограничена тем фактом, что tm_year
используется 32-битное целое число со знаком, начиная с 1900 года. Это ограничивает год максимумом в 2 147 485 547 (2 147 483 647 + 1900). [12]
Были сделаны альтернативные предложения (некоторые из которых уже используются), такие как хранение миллисекунд или микросекунд с начала эпохи (обычно 1 января 1970 года или 1 января 2000 года) в 64-битном целом со знаком, обеспечивающем минимальный диапазон 300 000. лет с микросекундным разрешением. [13] [14] В частности, повсеместное использование в Java 64-битных длинных целых чисел для представления времени в виде «миллисекунд с 1 января 1970 года» будет корректно работать в течение следующих 292 миллионов лет. Другие предложения по новым представлениям времени обеспечивают различную точность, диапазоны и размеры (почти всегда шире 32 бит), а также решают другие связанные проблемы, такие как обработка дополнительных секунд . В частности, TAI64 [15] представляет собой реализацию стандарта Международного атомного времени (TAI), текущего международного стандарта реального времени для определения секунды и системы отсчета.
time_t
. [17]time_t
как для 32-битной, так и для 64-битной архитектуры. Приложения, скомпилированные для более старой версии NetBSD с 32-разрядной версией, time_t
поддерживаются через уровень двоичной совместимости, но такие старые приложения по-прежнему будут страдать от проблемы Y2038. [18]time_t
как для 32-битной, так и для 64-битной архитектуры. В отличие от NetBSD здесь нет уровня двоичной совместимости. Таким образом, приложения, ожидающие 32-разрядной версии time_t
, и приложения, использующие что-либо иное для time_t
хранения значений времени, могут выйти из строя. [19]time_t
только для 64-битных архитектур; чистый 32-битный ABI не был изменен из-за обратной совместимости. [20] Начиная с версии 5.6 от 2020 года, 64-разрядная версия time_t
поддерживается и в 32-разрядных архитектурах. Это было сделано в первую очередь ради встраиваемых систем Linux . [21]time_t
на 32-разрядных платформах с соответствующими версиями Linux. Эту поддержку можно активировать, определив макрос препроцессора _TIME_BITS
при 64
компиляции исходного кода. [22]time_t
для всех 32-битных и 64-битных архитектур, кроме 32-битной i386, которая вместо этого использует подписанную 32-битную версию time_t
. [23]time_t
. Поскольку это была новая среда, особых мер предосторожности в отношении совместимости не было. [20]struct nfstime4 {int64_t seconds; uint32_t nseconds;}
с декабря 2000 года. [24] Версия 3 поддерживает беззнаковые 32-битные значения как struct nfstime3 {uint32 seconds; uint32 nseconds;};
. [25] Значения больше нуля в поле секунд обозначают даты после 0 часов, 1 января 1970 года. Значения меньше нуля в поле секунд обозначают даты до 0 часов, 1 января 1970 года. В обоих случаях Поле nсекунд (наносекунд) должно быть добавлено к полю секунд для окончательного представления времени.time_t
. [29] В рамках работы по обеспечению соответствия требованиям Y2K, которая проводилась в 1998 году, CRTL был модифицирован для использования 32-битных целых чисел без знака для представления времени; продление диапазона time_t
до 7 февраля 2106 г. [30]FROM_UNIXTIME()
, UNIX_TIMESTAMP()
и CONVERT_TZ()
обрабатывают 64-битные значения на платформах, которые их поддерживают. Сюда входят 64-разрядные версии Linux, MacOS и Windows. [32] [33] В старых версиях встроенные функции, например, UNIX_TIMESTAMP()
возвращают 0 после 03:14:07 UTC 19 января 2038 года. [34]