Экранирование литералов

В системе форматирования Luxon ключевым механизмом преобразования объектов DateTime в строки выступает метод toFormat. Он использует набор токенов (yyyy, MM, dd, HH и т.д.), которые интерпретируются как структурные элементы даты и времени. Любой текст, не являющийся токеном, рассматривается как потенциальный литерал и требует явного экранирования, чтобы не быть ошибочно распознанным как часть форматной инструкции.

Литералы в форматной строке — это фиксированные фрагменты текста, которые должны быть выведены без изменений: пробелы, знаки препинания, слова, разделители. Без экранирования такие фрагменты могут конфликтовать с системой токенов, особенно если содержат символы, совпадающие с именами форматных директив.


Механизм интерпретации форматной строки

При обработке строки формата Luxon выполняет последовательный разбор:

  1. Распознавание токенов даты и времени
  2. Интерпретация символов, не входящих в токены
  3. Обработка литералов в соответствии с правилами экранирования

Проблема возникает в том, что часть обычных символов может быть интерпретирована как управляющие конструкции. Например, последовательность yyyy всегда трактуется как год, даже если она является частью текстовой строки.


Экранирование через квадратные скобки

Наиболее читаемый и распространённый способ экранирования — использование квадратных скобок:

DateTime.now().toFormat("dd [декабря] yyyy")

Любой текст внутри [...] выводится буквально, без анализа на токены.

Принцип работы

  • Всё внутри [ и ] игнорируется парсером токенов
  • Символы внутри могут содержать любые буквы, цифры и знаки
  • Нет необходимости экранировать пробелы или пунктуацию

Пример сложной строки

DateTime.now().toFormat("HH:mm [часов, зона:] ZZZZ")

Результат:

14:30 часов, зона: GMT+3

Квадратные скобки удобны для длинных текстовых вставок, особенно в локализованных форматах.


Экранирование через одинарные кавычки

Второй механизм — использование одинарных кавычек:

DateTime.now().toFormat("dd 'декабря' yyyy")

Любой текст внутри кавычек трактуется как литерал.

Особенности поведения

  • Кавычки блокируют интерпретацию токенов внутри
  • Сам символ кавычки не выводится
  • Используется исторически как совместимый с Moment.js стиль

Ограничение

Если внутри литерала требуется сам символ ', его необходимо удваивать:

DateTime.now().toFormat("dd 'дня ''зимы''' yyyy")

Это создаёт сложные для чтения конструкции при частом использовании апострофов.


Экранирование апострофов

Апостроф в формате играет двойную роль: он обозначает начало и конец литерала. Чтобы вставить сам символ ', применяется удвоение:

DateTime.now().toFormat("yyyy 'год''а'")

Результат:

2026 года

Логика:

  • первая ' закрывает литерал
  • '' интерпретируется как один символ '
  • последняя ' снова открывает или закрывает контекст

Такая модель требует аккуратного построения строк при динамической генерации форматов.


Взаимодействие литералов и токенов

Ключевая особенность системы заключается в том, что токены распознаются до обработки литералов. Это означает:

  • любые совпадения с токенами вне литералов будут интерпретированы как формат
  • литералы полностью блокируют анализ содержимого

Пример конфликта

DateTime.now().toFormat("yyyy MM dd at HH:mm")

Без экранирования at не является проблемой, но если используется конструкция вроде:

DateTime.now().toFormat("yyyy MM dd HHa")

a может быть интерпретировано как AM/PM токен, что приведёт к искажению результата.

Корректная версия:

DateTime.now().toFormat("yyyy MM dd HH [at] a")

Смешивание квадратных скобок и кавычек

Оба способа экранирования могут использоваться совместно в одной строке:

DateTime.now().toFormat("dd [день] 'месяца' yyyy")

Логика применения:

  • квадратные скобки — для статических фраз и длинных вставок
  • кавычки — для компактных фрагментов и совместимости

При этом вложенность не поддерживается:

// некорректно
"dd ['месяц'] yyyy"

Особенности локализации и литералов

При использовании локализованных форматов литералы часто содержат грамматические связки:

DateTime.now().setLocale('ru').toFormat("d MMMM 'года'")

В этом случае:

  • токен MMMM зависит от локали
  • литерал 'года' остаётся неизменным

Для англоязычных форматов аналогично:

DateTime.now().toFormat("MMMM d, yyyy 'at' HH:mm")

Типичные ошибки при экранировании

1. Отсутствие экранирования текста

DateTime.now().toFormat("yyyy year MM month")

year и month могут интерпретироваться как некорректные токены или игнорироваться.


2. Неправильное использование апострофов

DateTime.now().toFormat("yyyy 'year's end'")

Ошибка возникает из-за разрыва литерала.

Корректный вариант:

DateTime.now().toFormat("yyyy 'year''s end'")

3. Путаница между квадратными скобками и кавычками

DateTime.now().toFormat("yyyy [year's] end")

Здесь символ ' внутри скобок безопасен, но смешение стилей ухудшает читаемость при сложных форматах.


Композиция сложных форматов

В реальных сценариях формат может содержать одновременно дату, время и текстовые конструкции:

DateTime.now().toFormat(
  "cccc, dd [декабря] yyyy 'года' в HH:mm:ss"
)

Разбор:

  • cccc — день недели
  • dd — день месяца
  • [декабря] — фиксированное слово
  • yyyy — год
  • 'года' — падежная форма
  • HH:mm:ss — время

Такой подход позволяет создавать шаблоны, близкие к естественному языку, без потери структурной точности.


Семантика выбора способа экранирования

Выбор между квадратными скобками и кавычками определяется структурой строки:

  • квадратные скобки обеспечивают визуальное разделение и устойчивость к сложным символам
  • кавычки удобны для коротких слов и совместимости с существующими форматами
  • апострофы требуют строгого контроля при вложенных конструкциях

При проектировании форматных шаблонов предпочтение обычно отдаётся квадратным скобкам как более предсказуемому и читаемому механизму, особенно в многоязычных приложениях.