ISO 8601 и как записать дату однозначно
· 4 мин чтения
ISO 8601 существует потому, что 03/04/2026 — это март в Америке и апрель во всём остальном мире. Запись 2026-04-03 снимает двусмысленность, правильно сортируется как текст и есть то, что должен принимать любой интерфейс.
03/04/2026 — это 3 апреля почти во всём мире и 4 марта в Соединённых Штатах. По одной лишь строке понять, что имелось в виду, невозможно, и оба прочтения совершенно разумны. Каждый год эта двусмысленность порождает сорванные сроки, двойные брони и хотя бы одну памятную аварию.
ISO 8601 — международный стандарт, который её устраняет.
Основной формат
2026-04-03T14:30:00Z
Слева направо, от старшей единицы к младшей:
2026-04-03— год, месяц, день, каждый с ведущим нулём, всегда в этом порядкеT— разделитель даты и времени, обязательный в строгой форме14:30:00— часы, минуты, секунды по 24-часовым часамZ— обозначение пояса.Zозначает ровно UTC
Дело именно в порядке. Поскольку составляющие идут от самой значимой к наименее значимой, строка ISO 8601 правильно сортируется как обычный текст. При простом сравнении строк 2026-04-03 идёт раньше 2026-04-10, чего не удаётся ни одному другому распространённому формату. Одно это свойство оправдывает стандарт.
Обозначения пояса
Годятся три формы, и значат они разное:
| Форма | Значение |
|---|---|
2026-04-03T14:30:00Z |
14:30 UTC. Однозначно |
2026-04-03T14:30:00+05:45 |
14:30 местного времени в поясе, опережающем UTC на 5 ч 45 мин. Однозначно |
2026-04-03T14:30:00 |
14:30 в неуказанном поясе. Не метка времени |
Беду приносит третья форма. Это местные дата и время — показание часов без всякой возможности разместить его на оси времени. Передать такое через границу системы и надеяться, что другая сторона предположит тот же пояс, что и вы, — это ошибка, ждущая развёртывания в другом регионе.
Заметьте также, чем смещение не является: +05:45 сообщает смещение Непала, а не то, что метка времени из Непала. Смещения — не пояса: одно и то же смещение делят несколько поясов, а смещение пояса меняется. Ведите идентификатор рядом, если нужно знать где.
RFC 3339 — профиль, который вам, скорее всего, и нужен
ISO 8601 огромен. Он допускает недельные даты (2026-W14-5), порядковые даты (2026-093), дробные единицы и усечённую форму без века. Почти ничего из этого в интерфейсе вам не нужно.
RFC 3339 — ужатый профиль для интернет-протоколов. Он требует полной даты, требует обозначения пояса и допускает в качестве разделителя либо T, либо пробел. Когда применительно к интерфейсу говорят «формат ISO», почти всегда имеют в виду RFC 3339.
Полезное правило: принимайте всё, что переварит хороший разборщик; выдавайте только строгий RFC 3339 с Z.
Длительности и интервалы
Используются реже, и знать их стоит на случай встречи.
Длительности начинаются с P от «период», а T отделяет часть даты от части времени:
P3Y6M4D— три года, шесть месяцев, четыре дняPT1H30M— час тридцать минутP1DT12H— сутки двенадцать часов
T не факультативна: P1M — это месяц, PT1M — минута. Это классическая ошибка с длительностями ISO 8601.
Интервалы соединяют две точки косой чертой: 2026-04-03T14:00Z/2026-04-03T16:00Z — либо точку и длительность: 2026-04-03T14:00Z/PT2H.
Структурированные данные HowTo на этом сайте используют синтаксис длительностей — PT2M для двухминутного шага, — потому что schema.org предписывает длительности ISO 8601.
Недельные даты и ловушка внутри них
2026-W14-5 — это пятница четырнадцатой недели ISO 2026 года. Недели ISO начинаются с понедельника, а неделя 1 — та, что содержит первый четверг января.
Следствие, на котором спотыкаются: год недели ISO не всегда совпадает с календарным годом. 1 января 2027 года попадает в 53-ю неделю ISO 2026 года. Код форматирования, соединяющий номер недели ISO с календарным годом, каждый год на несколько дней даёт неверную дату — а в большинстве языков спецификаторы формата выглядят почти одинаково (YYYY против GGGG или %Y против %G).
Практические правила
- Храните в UTC, выдавайте с
Z. У2026-04-03T14:30:00Zвезде ровно одно значение. - Никогда не выдавайте голые местные дату и время через границу. Если пояс не приложить, у вас нет метки времени.
- Дополняйте нулями всё.
2026-4-3— не годный ISO 8601, хотя большинство разборщиков его примет. - Используйте разделители
-и:. Компактная форма (20260403T143000Z) законна, но недружелюбна, и часть разборщиков её отвергает. - Ведите идентификатор пояса отдельно, когда нужно знать где, а не только какое смещение.
Europe/Londonпереживёт смену правил,+01:00— нет.
Подводные камни разбора
Даже при наличии стандарта именно разбор оказывается местом, где всё ломается.
Конструктор Date в JavaScript непоследователен для входа не по стандарту. new Date('2026-04-03') разбирается как полночь UTC. new Date('2026-04-03T00:00:00') — без обозначения пояса — разбирается как местная полночь. Разница между ними равна вашему смещению, а значит, один и тот же код даёт разные даты в зависимости от места запуска. Всегда указывайте обозначение пояса.
Двузначные годы двусмысленны, и их следует отвергать. ISO 8601 допускает усечённую форму; принимать её не должно почти ничто. 26-04-03 может быть 1926 или 2026 годом, а скользящее окно, которое это решает, — политическое решение, спрятанное в разборщике.
Доли секунды бывают разной точности. 14:30:00.5, 14:30:00.500 и 14:30:00.500000 одинаково допустимы и обозначают один и тот же момент. Разборщик, сравнивающий строки вместо моментов, с этим не согласится.
Запятая законна. ISO 8601 допускает 14:30:00,5 — десятичную запятую — и даже предпочитает её. Большинство разборщиков её отвергает. Если вы принимаете данные из европейской системы, будьте готовы.
У полуночи два написания. 24:00:00 одного дня — тот же момент, что 00:00:00 следующего, и обе записи допустимы. Выдавайте вторую форму, принимайте обе.
Замечание о сортировке
Сортируемость ISO 8601 верна только для строк с одинаковым представлением пояса. 2026-04-03T14:00:00Z и 2026-04-03T10:00:00-05:00 — один и тот же момент, но как строки вторая идёт раньше.
Если вы сортируете метки времени как текст — в журнале, в имени файла, в текстовом столбце базы, — сначала приведите их все к UTC с Z. Иначе порядок окажется свойством форматирования, а не времени.