Метки времени Unix: секунды или миллисекунды, часовые пояса и проблема 2038 года
Когда наступает 1700000000? Почему некоторые системы используют 13-значные числа? Почему время сдвинулось ровно на три часа? Большинство ошибок со временем исчезает, если разобраться в нескольких понятиях.
Что такое метка времени Unix
Метка времени Unix (Unix-время, epoch time) — это одно целое число, равное количеству секунд, прошедших с 00:00:00 UTC 1 января 1970 года, то есть с эпохи Unix. 0 — это 1970-01-01 00:00:00 UTC, а 1700000000 — 2023-11-14 22:13:20 UTC.
Представлять момент одним числом очень удобно. Разница между двумя моментами вычисляется одним вычитанием, сортировка и сравнение тривиальны, а один и тот же момент имеет одинаковое значение везде, независимо от часового пояса и формата даты.
0 → 1970-01-01 00:00:00 UTC
1700000000 → 2023-11-14 22:13:20 UTC
1735689600 → 2025-01-01 00:00:00 UTC
2147483647 → 2038-01-19 03:14:07 UTC
10 цифр или 13: секунды или миллисекунды?
Современная метка времени в секундах состоит из 10 цифр. Но Date.now() в JavaScript и System.currentTimeMillis() в Java возвращают миллисекунды — 13 цифр. Если их перепутать, получатся даты вроде 21 января 1970 года или на пятьдесят тысяч лет в будущем.
Посчитайте цифры: 10 — секунды, 13 — миллисекунды, 16 — микросекунды. Если API не указывает единицу измерения, уточните её и при переводе умножайте или делите на 1000.
У метки времени нет часового пояса
Главное: у метки времени нет часового пояса. 1700000000 — один и тот же момент в Москве и в Нью-Йорке. Часовой пояс применяется только при показе числа в виде понятной человеку даты: одно и то же значение — это 22:13 по UTC и 01:13 следующего дня по Москве (UTC+3).
Классическая ошибка «время сдвинулось на три часа» возникает при нарушении этого правила: хранят в UTC, а показывают как местное время, или сохраняют местное время без смещения и читают его как UTC. Храните и передавайте время в UTC (или в виде меток времени), а показывайте — в часовом поясе пользователя.
Ловушки летнего времени
В России сейчас нет перехода на летнее время, но в США и большей части Европы часы весной переводят вперёд, а осенью назад. Поэтому утверждение «Нью-Йорк отстаёт от Москвы на 8 часов» верно лишь часть года, а в остальное время разница составляет 7 часов.
Используйте названия зон IANA, например America/New_York или Europe/Moscow, а не фиксированные смещения вроде -05:00, чтобы переходы учитывались автоматически. Планируя встречи с зарубежными командами или настраивая задания, проверяйте фактическое смещение на нужную дату в калькуляторе часовых поясов.
Проблема 2038 года
Если хранить метку времени в знаковом 32-битном целом, её максимум — 2 147 483 647, то есть 03:14:07 UTC 19 января 2038 года. Секундой позже значение переполняется, становится отрицательным и перескакивает в 1901 год. Это и есть проблема 2038 года.
Современные ОС и языки в основном используют 64-битное время, но 32-битные значения сохранились в старых встраиваемых устройствах, столбцах INT баз данных и форматах файлов. Системы, работающие с далёкими датами — долгосрочными сертификатами или 30-летними кредитами, — могут упереться в предел уже сегодня, поэтому в новых проектах используйте 64-битные целые или полноценные типы дат.
Високосные секунды и точность
Unix-время считает каждые сутки равными ровно 86 400 секундам и игнорирует високосные секунды. Поэтому оно может совсем немного отличаться от астрономически точного прошедшего времени, что обычные приложения могут спокойно не учитывать. Генеральная конференция по мерам и весам решила отменить високосные секунды к 2035 году.
Вставьте число в конвертер меток времени AIBIZAP: он сам определит секунды или миллисекунды и покажет дату по UTC и в выбранном поясе. Для сравнения местного времени используйте калькулятор часовых поясов, а для заданий, повторяющихся в заданное время, — генератор cron.