Разбор строк в формате даты и времени в Luxon основан на строгом сопоставлении входной строки с набором форматных токенов. Каждый токен представляет собой атомарное правило интерпретации символов, и вся операция парсинга сводится к последовательному совпадению этих правил с текстом.
Токенизация формата выполняет две ключевые функции: определение границ значений и интерпретацию их семантики. При несовпадении хотя бы одного токена с соответствующим фрагментом строки результатом становится невалидная дата.
Форматная строка в Luxon представляет собой последовательность токенов, каждый из которых соответствует определённому компоненту даты или времени.
Пример:
DateTime.fromFormat("2026-01-25 14:30", "yyyy-MM-dd HH:mm");
Здесь строка разбивается на логические сегменты:
yyyy → год (4 цифры)MM → месяц (2 цифры)dd → деньHH → часы (24-часовой формат)mm → минутыРазбор выполняется слева направо без обратного поиска. Каждый символ входной строки должен быть объяснён соответствующим токеном.
Одним из фундаментальных правил является зависимость поведения парсинга от длины токена.
y — минимальная длина (1–6 цифр)yy — две цифрыyyyy — строго 4 цифрыDateTime.fromFormat("26", "yy"); // 2026
DateTime.fromFormat("2026", "yyyy"); // 2026
Если формат требует фиксированной длины, несоответствие длины приводит к неуспешному разбору.
M — 1–2 цифры (1–12)MM — строго 2 цифрыd — 1–2 цифрыdd — строго 2 цифрыDateTime.fromFormat("3", "MM"); // невалидно
DateTime.fromFormat("03", "MM"); // валидно
Сопоставление не выполняет автоматического дополнения нулями при строгих токенах.
Парсер Luxon не выполняет семантического анализа структуры строки. Он работает по принципу позиционного соответствия:
Пример:
DateTime.fromFormat("2026-01-25T14:30", "yyyy-MM-dd HH:mm");
Несоответствие возникает из-за символа T, который не
описан в формате.
Для корректного разбора:
DateTime.fromFormat("2026-01-25T14:30", "yyyy-MM-dd'T'HH:mm");
Любые символы, не являющиеся токенами, трактуются как литералы только при явном указании.
DateTime.fromFormat("2026 год 25-01", "yyyy 'год' dd-MM");
Ключевой принцип: всё внутри одинарных кавычек не интерпретируется как токены.
Некоторые символы требуют обязательного экранирования:
:-H — 0–23HH — 00–23h — 1–12 (12-часовой формат)hh — 01–12При использовании 12-часового формата обязательным становится токен AM/PM:
DateTime.fromFormat("03:30 PM", "hh:mm a");
Токен a определяет период суток:
AMPMНесоответствие регистра или отсутствия токена приводит к ошибке парсинга.
m, mm — минутыs, ss — секундыЭти токены не допускают дробных значений и строго интерпретируют числовую часть строки.
Работа с временными зонами требует отдельного набора токенов:
Z — смещение от UTC в формате ±HH:mmZZ — расширенный форматz — название зоны (ограниченная поддержка)Пример:
DateTime.fromFormat("2026-01-25 14:30 +05:00", "yyyy-MM-dd HH:mm Z");
Сопоставление смещения требует точного совпадения структуры:
+ или - обязателен;При парсинге Luxon не пытается «угадать» значение. Несоответствие
приводит к созданию невалидного объекта DateTime.
const dt = DateTime.fromFormat("2026/01/25", "yyyy-MM-dd");
dt.isValid; // false
Основные причины невалидности:
Luxon использует строгую модель соответствия без автоматической нормализации входных данных.
Отсутствуют автоматические преобразования:
"1" не становится "01" при
MM;"2pm" не распознаётся как валидное время без
a;"2026-1-5" не интерпретируется как
yyyy-MM-dd.Эта строгость делает токенизацию предсказуемой и исключает неоднозначные разборы.
При наличии пересекающихся токенов приоритет определяется порядком следования в формате.
Пример:
DateTime.fromFormat("20260125", "yyyyMMdd");
Разбор выполняется последовательно:
yyyy → 2026MM → 01dd → 25Если структура строки не позволяет однозначно выделить сегменты, парсер не выполняет перераспределение символов.
Некоторые токены допускают повторение, но их семантика не меняется:
DateTime.fromFormat("2026 2026 01 25", "yyyy yyyy MM dd");
Второй yyyy интерпретируется независимо, без проверки
логической целостности года.
Часть токенов зависит от локали:
Пример:
DateTime.fromFormat("25 janvier 2026", "dd LLLL yyyy", { locale: "fr" });
Токен LLLL соответствует полному названию месяца в
выбранной локали. При несоответствии локали разбор не выполняется.
Строки с неоднозначной структурой требуют точного формата, иначе результат становится неопределённым.
Пример неоднозначности:
01-02-03
Без формата невозможно определить:
Токенизация устраняет неоднозначность через явное сопоставление:
DateTime.fromFormat("01-02-03", "yy-MM-dd");
Любые пробелы считаются значимыми символами, если они присутствуют в формате.
DateTime.fromFormat("2026-01-25 14:30", "yyyy-MM-dd HH:mm");
При изменении строки:
DateTime.fromFormat("2026-01-25T14:30", "yyyy-MM-dd HH:mm");
результат становится невалидным из-за различия разделителя.
Luxon не допускает частичного успешного парсинга. Строка должна быть полностью объяснена форматными токенами.
DateTime.fromFormat("2026-01-25 extra", "yyyy-MM-dd");
остаток extra приводит к ошибке, даже если первые токены
совпали корректно.
Для анализа сопоставления токенов используется объясняющий режим:
DateTime.fromFormatExplain("2026-01-25", "yyyy-MM-dd");
Он позволяет определить:
Механизм разбора можно представить как последовательную детерминированную машину:
Такое поведение обеспечивает предсказуемость, но требует точного соответствия между форматом и входными данными без допуска к интерпретации или эвристике.