Метки времени Unix и эпоха: проблема 2038 года, объяснение

Опубликовано: 9:00 AM , от Редакция Vremyav.ru

Объяснение меток времени Unix: секунды с эпохи 1970 года, преобразование в UTC, переполнение в 2038 году в 03:14:07 UTC, 64-битное исправление и високосные секунды.

Цифровые часы, переключающиеся с 03:14:07 UTC 19 января 2038 года, иллюстрирующие переполнение 32-битного времени Unix со знаком

Что такое Unix-время?

Unix-время — это одно число: количество секунд, прошедших с эпохи Unix, определённой как 00:00:00 UTC 1 января 1970 года. Вот и всё. Ни часового пояса, ни строки с датой, ни названий месяцев — просто целое число, увеличивающееся на единицу каждую секунду.

Поскольку эпоха фиксирована и универсальна, метка времени, например 1700000000, означает один и тот же момент в любой точке Земли. Сервер в Токио и ноутбук в Чикаго согласятся, что это 14 ноября 2023 года, 22:13:20 UTC. Локальное отображение различается в зависимости от часового пояса, но базовое число никогда не меняется.

Одно намеренное упрощение: Unix-время игнорирует високосные секунды. Оно предполагает, что каждый день длится ровно 86 400 секунд, что не совсем соответствует астрономической реальности, но сохраняет чистоту арифметики. Подробнее об этом ниже.

Почему инженеры их любят

Метки времени повсюду в программном обеспечении — время изменения файлов, записи в базах данных, ответы API, поля срока действия JWT, строки журналов — и не зря:

  • Это одно значение. Одно целое число хранит полную дату и время. Никакого разбора, никакой двусмысленности между ММ/ДД и ДД/ММ.
  • Они не зависят от часового пояса. Число всегда в UTC. Вы конвертируете в местное время только когда показываете его человеку.
  • Их легко сравнивать и сортировать. Какое событие произошло раньше? Меньшее целое число. Продолжительность между двумя событиями? Вычтите их; ответ в секундах.
  • Они компактно хранятся. Одно 4- или 8-байтовое целое число против форматированной строки.

Вот почему так много инфраструктуры внутри использует секунды эпохи, даже если интерфейс показывает вам дружелюбное 2026-07-23. Если вы хотите переключаться между двумя представлениями, конвертер меток времени Unix выполняет перевод в обоих направлениях.

Чтение метки времени: практический пример

Возьмём метку времени 1000000000 — знаменитую, потому что её переполнение транслировалось в прямом эфире среди энтузиастов Unix.

Чтобы прочитать её вручную, вы делите секунды на более крупные единицы. Примерно 1 000 000 000 секунд — это около 31,7 года (год составляет ~31 556 952 секунды). Прибавьте это к эпохе 1970 года, и вы попадёте в 2001 год. Точный момент — 09 сентября 2001 года, 01:46:40 UTC.

Вы редко делаете эту арифметику вручную — в каждом языке есть встроенная функция. В Python:

```python from datetime import datetime, timezone datetime.fromtimestamp(1000000000, tz=timezone.utc)

2001-09-09 01:46:40+00:00

```

Ключевой момент: преобразование всегда привязано к UTC. Функция превращает необработанное количество секунд в календарную дату, двигаясь вперёд от эпохи. Если вам нужно местное время, вы применяете смещение часового пояса после преобразования в UTC — сама метка времени не содержит информации о часовом поясе.

Проблема 2038 года

Вот где история становится интересной — и где у многих в остальном хорошо построенных систем внутри тикают часы.

В течение десятилетий стандартный тип C, используемый для хранения Unix-времени, time_t, обычно был 32-битным целым числом со знаком. 32-битное целое число со знаком может представлять значения от −2 147 483 648 до 2 147 483 647. Эта верхняя граница и есть проблема.

Считая секунды от эпохи 1970 года, значение 2 147 483 647 достигается в 03:14:07 UTC 19 января 2038 года. Через одну секунду счётчик должен стать 2 147 483 648 — но это число не помещается в 32-битное целое со знаком. Вместо того чтобы продолжать расти, биты переполняются и заворачиваются до самого отрицательного значения, −2 147 483 648.

Отрицательная метка времени интерпретируется как время до эпохи. Таким образом, часы не просто останавливаются — они перескакивают назад к 13 декабря 1901 года. Любая система, доверявшая своему 32-битному time_t, внезапно считает, что находится в начале двадцатого века.

Это часто называют проблемой Y2K38 или проблемой Unix Millennium, и структурно это тот же вид переполнения фиксированной разрядности, который вызвал панику по поводу 2000 года — только дальше по времени и основанный на ограничениях двоичных целых чисел, а не на двузначных годах.

Где это действительно проявляется

Современные 64-битные настольные компьютеры и серверы были в значительной степени исправлены годы назад. Риск сосредоточен в местах, которые трудно обновить:

  • Встраиваемые и промышленные системы. Маршрутизаторы, контроллеры, медицинские устройства, автомобильные ЭБУ и оборудование Интернета вещей, которое поставлялось с 32-битным time_t и может работать без изменений 20+ лет. Многие устройства, развёрнутые сегодня, всё ещё будут эксплуатироваться в 2038 году.
  • Устаревший код на C. Приложения, скомпилированные со старым определением time_t, особенно когда этот тип проник в дисковые форматы или сетевые протоколы.
  • Старые базы данных и файловые системы. Форматы хранения, которые упаковывали метки времени в 32-битные поля. Некоторые старые системы уже проявляют симптомы при обработке дат в далёком будущем — подумайте об ипотеке на 20 лет или сроке действия сертификата, который достигает 2038 года.

Режим отказа не всегда является драматическим сбоем. Иногда это тонкая ошибка в вычислении даты: просроченный токен, который считается действительным, порядок сортировки, который инвертируется, запланированная задача, которая запускается в 1901 году.

Исправление: 64-битное время

Средство правления просто в принципе — расширить time_t до 64 бит. 64-битное целое число со знаком может считать секунды далеко за любой практический горизонт: точка переполнения находится примерно через 292 миллиарда лет в будущем, что с комфортом превышает ожидаемое время жизни Солнца.

Большинство современных операционных систем уже сделали этот шаг. 64-битный Linux использует 64-битный time_t; даже 32-битный Linux получил поддержку 64-битного времени в ядре и glibc в последние годы. Сложность не в самом исправлении — она в том, чтобы найти и пересобрать каждую часть прошивки, каждый формат хранения и каждый сторонний двоичный файл, который всё ещё предполагает 32 бита. Эта работа по аудиту и есть настоящий проект 2038 года.

Как вписываются високосные секунды

Астрономическое время и атомное время немного расходятся, поэтому официальный UTC время от времени вставляет високосную секунду, чтобы синхронизировать часы с вращением Земли. Unix-время по замыслу делает вид, что их не существует — оно жёстко задаёт 86 400 секунд в сутках.

Когда происходит високосная секунда, системы обычно "размазывают" её — распределяя дополнительную секунду по окну (Google популяризировал 24-часовое размазывание), чтобы ни одним часам никогда не пришлось показывать невозможное 23:59:60. Итог: метки времени Unix остаются гладкими и монотонными ценой небольшого расхождения со строгим UTC на долю секунды во время размазывания. Для практически всего программного обеспечения это именно тот компромисс, который вам нужен. Переполнение 2038 года — это проблема разрядности целого числа; високосные секунды — это отдельная, гораздо меньшая определительная особенность — не путайте их.

Ключевые выводы

  • Unix-время — это секунды с 00:00:00 UTC 1 января 1970 года, високосные секунды игнорируются.
  • Это одно целое число, не зависящее от часового пояса — легко хранить, сравнивать и сортировать.
  • Преобразование всегда относительно UTC; местное время применяется после.
  • 32-битный time_t со знаком переполняется в 03:14:07 UTC 19 января 2038 года, заворачиваясь до отрицательного значения и перескакивая в 1901 год.
  • Исправление — 64-битный time_t; усилия заключаются в аудите встраиваемых и устаревших систем.

Хотите увидеть это в действии? Вставьте любое значение эпохи в конвертер меток времени Unix, чтобы прочитать его как человеческую дату — или пойдите другим путём и превратите дату в её метку времени.

Часто задаваемые вопросы

Unix-время в секундах или миллисекундах?

Классическое Unix-время — в секундах. Однако JavaScript и многие веб-API используют миллисекунды с начала эпохи, поэтому значение типа 1700000000000 в 1000 раз больше. Быстрая подсказка: метка времени на основе секунд для недавней даты имеет 10 цифр; миллисекундная — 13. Если сомневаетесь, проверьте порядок величины перед преобразованием.

Вызовет ли проблема 2038 года сбой моего телефона или ноутбука?

Почти наверняка нет. Современные 64-битные операционные системы уже используют 64-битный time_t, что отодвигает переполнение на миллиарды лет вперёд. Реальная угроза — в долгоживущих встраиваемых устройствах и старом программном обеспечении, которое всё ещё полагается на 32-битное время и может не быть обновлено до 2038 года.

Может ли Unix-время быть отрицательным?

Да. Отрицательные значения представляют моменты до эпохи 1970 года — например, -1 — это 31 декабря 1969 года, 23:59:59 UTC. Именно это и производит 32-битное переполнение в 2038 году, поэтому часы, кажется, перескакивают обратно в 1901 год.

Почему Unix-время игнорирует високосные секунды?

Чтобы математика была простой и предсказуемой. Считая каждый день равным ровно 86 400 секундам, длительности вычисляются простым вычитанием, а метки времени остаются монотонными. Небольшое несоответствие с астрономическим UTC обрабатывается "размазыванием" високосной секунды, что почти все приложения предпочитают работе с граничным случаем 23:59:60.

Как преобразовать метку времени без написания кода?

Используйте онлайн-инструмент. конвертер меток времени Unix принимает значение эпохи и мгновенно показывает соответствующую дату и время в UTC и местном времени, а также преобразует календарные даты обратно в метки времени.

Текущее время в этих городов:

Амстердам · Барселона · Пекин · Берлин · Копенгаген · Дубай · Лондон · Лос-Анджелес · Мадрид · Мехико · Москва · Мумбаи · Нью-Йорк · Париж · Рим · Шанхай · Сидней · Токио

Текущее время в странах:

🇦🇺 Австралия | 🇧🇷 Бразилия | 🇨🇦 Канада | 🇨🇳 Китай | 🇫🇷 Франция | 🇩🇪 Германия | 🇮🇳 Индия | 🇮🇩 Индонезия | 🇮🇹 Италия | 🇯🇵 Япония | 🇲🇽 Мексика | 🇳🇱 Нидерланды | 🇷🇺 Россия | 🇸🇦 Саудовская Аравия | 🇰🇷 Южная Корея | 🇪🇸 Испания | 🇸🇪 Швеция | 🇨🇭 Швейцария | 🇬🇧 Соединённое Королевство |

Текущее время в часовые пояса:

UTC | GMT | PST | MST | CST | EST | EET | IST | JST | AEST | SAST | MSK | NZST

Бесплатно виджеты для веб-мастеров:

Бесплатный аналоговый виджет часов | Бесплатный цифровой часы-виджет | Бесплатный текстовый часы-виджет | Бесплатный словесный часы-виджет