Проблема 2038 года ( также известная как Y2038 , [1] Y2K38 , супербактерия Y2K38 или Эпохалипс [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 года , разница лишь в том, что в задаче 2000 года речь идет о числах с основанием 10 , тогда как в задаче 2038 года речь идет о числах с основанием 2 .
Аналогичные ограничения по хранению будут достигнуты в 2106 году , когда системы, хранящие время Unix как беззнаковое (а не знаковое) 32-битное целое число, переполнятся 7 февраля 2106 года в 06:28:15 UTC.
Компьютерные системы, использующие время для критических вычислений, могут столкнуться с фатальными ошибками, если проблема 2038 года не будет решена. Некоторые приложения, использующие будущие даты, уже столкнулись с этой ошибкой. [4] [5] Наиболее уязвимыми являются те системы, которые обновляются редко или никогда не обновляются, такие как устаревшие и встроенные системы . Современные системы и обновления программного обеспечения для устаревших систем решают эту проблему, используя 64-битные целые числа со знаком вместо 32-битных целых чисел, переполнение которых займет 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 ( California Air Resources Board ). [9]
В мае 2006 года появились сообщения о раннем проявлении проблемы Y2038 в программном обеспечении AOLserver . Программное обеспечение было разработано с помощью ляпа для обработки запроса к базе данных, который «никогда» не должен был бы истекать по времени. Вместо того, чтобы специально обрабатывать этот особый случай, первоначальный проект просто указал произвольную дату тайм-аута в будущем с конфигурацией по умолчанию, указывающей, что запросы должны истекать по истечении максимум одного миллиарда секунд. Однако один миллиард секунд до даты отсечки 2038 года — это 01:27:28 UTC 13 мая 2006 года, поэтому запросы, отправленные после этого времени, приведут к дате тайм-аута, которая будет выходить за пределы отсечки. Это привело к переполнению расчетов тайм-аута и возврату дат, которые на самом деле были в прошлом, что привело к сбою программного обеспечения. Когда проблема была обнаружена, операторам 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-битном целом числе, обеспечивая минимальный диапазон в 292 000 лет с микросекундным разрешением. [13] [14] В частности, использование Java и JavaScript 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 года. В обоих случаях поле nseconds (наносекунд) должно быть добавлено к полю секунд для окончательного представления времени.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]TIMESTAMP
и функции FROM_UNIXTIME()
, UNIX_TIMESTAMP()
и CONVERT_TZ()
обрабатывают беззнаковые 32-битные значения в 64-битных версиях Linux, macOS и Windows. [35] Это расширило диапазон до 2106-02-07 06:28:15 и позволило пользователям хранить такие значения временных меток в таблицах, не изменяя структуру хранилища и, таким образом, оставаясь полностью совместимыми с существующими пользовательскими данными.time_t
если не _USE_32BIT_TIME_T
определен макрос препроцессора. [36] Однако сам API Windows не подвержен ошибке 2038 года, поскольку Windows внутренне отслеживает время как количество 100-наносекундных интервалов с 1 января 1601 года в 64-битном знаковом целом числе, которое не переполнится до 30 828 года . [37]