Unix-время и проблема 2038 года: как компьютер хранит дату
Unix-время хранит момент как число секунд после 1 января 1970 года. Старый 32-битный счётчик закончится 19 января 2038 года и без исправления перепутает будущее с 1901 годом.

Unix-время хранит момент как число секунд после 1 января 1970 года. Старый 32-битный счётчик закончится 19 января 2038 года и без исправления перепутает будущее с 1901 годом.

Дальше вы переведёте несколько дат в секунды, отделите сам момент от часового пояса и увидите, почему замена 32 бит на 64 решает проблему на срок гораздо длиннее возраста Вселенной.
В статье вы узнаете:
Unix-время появилось в семействе операционных систем Unix, которое разрабатывали в Bell Labs с конца 1960-х годов. Компьютеру было удобнее хранить не фразу «26 августа 2026 года», а одно число, которое можно сравнивать, складывать и записывать в файл.
Нулевой точкой стала полночь 1 января 1970 года по UTC. Её называют эпохой Unix. В этот момент счётчик равен нулю. Через одну секунду он равен 1, через минуту 60, через сутки 86 400.
Unix timestamp является количеством секунд после эпохи Unix. В привычном POSIX-варианте дополнительные секунды, которые иногда вставляют в мировое время, не входят в отдельный непрерывный счёт.
Дата до эпохи получает отрицательное значение. Момент 31 декабря 1969 года, 23:59:59 UTC, можно записать как −1. Ноль здесь не начало времени и не рождение компьютеров, а выбранная точка отсчёта.
Современная библиотека GNU C описывает time_t именно как целое число секунд от 1 января 1970 года по UTC и отмечает, что POSIX.1-2024 требует для него не меньше 64 бит. [GNU C Library, Time Types]
Возьмём 2 января 1970 года, 00:00:00 UTC. После эпохи прошли ровно одни сутки. В сутках 24 часа, в часе 60 минут, в минуте 60 секунд.
1 × 24 × 60 × 60 = 86 400 секунд
Значит, timestamp этой полуночи равен 86 400. Для 3 января он равен 172 800. Дальше программа учитывает разную длину месяцев и високосные годы, но смысл остаётся тем же.
У 1 января 2000 года, 00:00:00 UTC, значение равно 946 684 800. Человеку число ничего не рассказывает. Программе оно удобно: более поздний момент получает большее значение, а разность двух значений даёт длительность в секундах.
Калькулятор единиц времени помогает перевести секунды в минуты, часы и дни. Для очень коротких интервалов используют миллисекунды, то есть тысячные доли секунды. В JavaScript время обычно считают именно в миллисекундах после той же эпохи.
Например, 86 400 секунд равны 86 400 000 миллисекунд. Конвертер дней в миллисекунды выполнит это умножение, а перевод миллисекунд в часы вернёт масштаб, который легче прочитать.
Один и тот же момент выглядит по-разному в Бишкеке, Москве и Лондоне. Unix timestamp при этом остаётся одним. Часовой пояс добавляют только при показе даты человеку.
Представьте прямую трансляцию. Зрители видят один гол одновременно, хотя местные часы показывают разное время. Timestamp ставит метку на самом событии. Часовой пояс переводит метку в местный календарь.
Поэтому строка «2026-08-26 10:00» неполна. Нужно знать, это 10:00 UTC, 10:00 в Бишкеке или 10:00 в Нью-Йорке. После выбора зоны строки превратятся в разные моменты и разные числа.
Правила зон тоже меняются. Государства переносят переходы на летнее время и меняют смещения. Именованная зона вроде Asia/Bishkek хранит набор правил, а не просто постоянное число часов. Подробно эта разница разобрана в статье о часовых поясах и календарных датах.
Не удаляйте зону из будущего расписания. Timestamp хорошо хранит уже выбранный момент. Фраза «каждый понедельник в 9:00 по Парижу» является календарным правилом, которому ещё предстоит вычислять новые моменты.
Бит хранит ноль или единицу. В 32-битном знаковом целом один бит отвечает за знак, а остальные задают величину. Максимальное положительное значение равно 231 − 1.
2³¹ − 1 = 2 147 483 647
Для Unix-времени это 19 января 2038 года, 03:14:07 UTC. Следующая секунда требует числа 2 147 483 648, которое уже не помещается в старый знаковый формат.
В обычном двоичном представлении со знаком разряды могут перейти к минимальному отрицательному значению −2 147 483 648. Если программа продолжит читать его как timestamp, она получит 13 декабря 1901 года, 20:45:52 UTC.
Такой переход называется переполнением. Он похож на механический счётчик километров, который после 999 999 возвращается к нулям. Только здесь возврат может испортить срок сертификата, дату платежа, журнал событий или условие «действует до».
Проблема возникает раньше самой даты. Система может уже сегодня записывать срок договора, сертификата или расписания после 2038 года. Если поле не принимает такое значение, ошибка появляется при создании записи, а не в январскую ночь.
Современный ноутбук с 64-битной системой обычно хранит время в широком формате. Но данные проходят через базы, сетевые протоколы, файловые форматы, библиотеки и встроенные устройства. Одного старого 32-битного поля достаточно, чтобы потерять дату.
Особенно внимательно проверяют оборудование, которое работает десятилетиями: промышленные контроллеры, сетевые устройства, автомобильные блоки, медицинскую технику и старые системы учёта. Их процессор может быть слабым, обновление дорогим, а формат данных закреплён в прошивке.
Само выражение «32-битное устройство» ещё не является диагнозом. Программа может хранить время в двух 32-битных словах или использовать отдельную календарную структуру. И наоборот, 64-битная программа может читать старый файл с 32-битной датой.
Версия 1 формата файлов часовых поясов TZif использовала 32-битные времена переходов, а новые версии добавили 64-битный блок. Спецификация требует уметь пережить границы диапазона и корректно работать с будущими правилами. [RFC 8536, формат TZif]
Поэтому аудит ищет не наклейку на корпусе, а все места хранения и обмена: тип переменной, колонку базы, сериализацию, API, файл, подпись сертификата и стороннюю библиотеку.
Знаковое 64-битное целое хранит значения до 263 − 1. Если считать секунды, положительного диапазона хватит примерно на 292 миллиарда лет после эпохи Unix. Практического календаря на такой срок у нас, мягко говоря, нет.
Современные системы переходят на 64-битный time_t, новые системные вызовы и широкие поля форматов. Но заменить тип в одной строке недостаточно. Старый двоичный файл и новая программа должны одинаково понимать длину и порядок данных.
Для проверки разработчики создают даты до и после границы: 19 января 2038 года, 03:14:07 и 03:14:08 UTC. Затем прогоняют их через сохранение, передачу, сортировку, арифметику и показ в разных зонах.
Полезно проверить и отрицательные значения, конец високосного дня, дальние сроки сертификатов и даты в базе. Ошибка часто находится не в системных часах, а в одном преобразовании числа в строку или обратно.
Главный вывод. Unix-время упрощает дату до счётчика секунд от 1970 года. Проблему 2038 создаёт не сама эпоха, а узкое 32-битное знаковое поле. Переход на 64 бит снимает числовую границу, но безопасность зависит от всей цепочки, которая хранит и передаёт время.
Напишите своё мнение, комментарий или предложение.