Использование нескольких форматов

Moment.js предоставляет механизм обработки входных строк даты, которые могут соответствовать различным шаблонам. Это особенно важно в случаях, когда источник данных неоднороден: пользовательский ввод, внешние API, импортированные файлы или исторические данные, где форматирование не унифицировано.

Основная идея заключается в передаче массива форматов в функцию парсинга. Библиотека последовательно проверяет строку даты по каждому шаблону до первого успешного совпадения.

Базовый принцип работы с массивом форматов

При вызове moment() можно передать не один формат, а несколько:

moment("2026-05-21", ["YYYY-MM-DD", "DD/MM/YYYY", "MM-DD-YYYY"]);

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

  1. Проверка на соответствие YYYY-MM-DD
  2. При неудаче — DD/MM/YYYY
  3. Затем MM-DD-YYYY

Первый подходящий формат завершает процесс парсинга.

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

Порядок форматов и его влияние

Порядок элементов в массиве имеет прямое значение. Moment.js не анализирует «наиболее вероятный» формат, а действует строго последовательно.

moment("01-02-2026", ["DD-MM-YYYY", "MM-DD-YYYY"]);

Здесь результат будет интерпретирован как 1 февраля 2026 года, поскольку первым проверяется формат DD-MM-YYYY.

Если поменять порядок:

moment("01-02-2026", ["MM-DD-YYYY", "DD-MM-YYYY"]);

результат изменится и будет трактоваться как 2 января 2026 года.

Подобное поведение требует строгого контроля порядка форматов при проектировании системы обработки дат.

Строгий режим парсинга

Moment.js поддерживает «строгий» режим, при котором формат должен совпадать полностью, без частичных соответствий.

moment("2026-5-1", ["YYYY-MM-DD"], true);

В строгом режиме строка "2026-5-1" не будет считана корректной для формата YYYY-MM-DD, так как ожидается строгое соответствие двухзначных компонентов месяца и дня.

При использовании массива форматов строгий режим применяется ко всем элементам списка:

moment("21/05/2026", ["YYYY-MM-DD", "DD/MM/YYYY"], true);

Если ни один формат не соответствует строго, результатом становится невалидная дата.

Смешивание ISO и пользовательских форматов

Moment.js поддерживает ISO 8601 как отдельный стандартный случай. При передаче массива форматов ISO может использоваться как один из вариантов или как отдельная ветка обработки.

moment("2026-05-21T14:30:00Z", ["YYYY-MM-DD", moment.ISO_8601]);

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

Использование moment.ISO_8601 позволяет интегрировать строгие стандарты обмена данными вместе с локальными форматами.

Комбинация локальных форматов

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

moment("21.05.2026", ["DD.MM.YYYY", "MM-DD-YYYY", "YYYY/MM/DD"]);

Подобные комбинации позволяют покрывать широкий спектр пользовательских привычек без необходимости предварительного преобразования строки.

Локальные форматы могут включать:

  • точки как разделители
  • слэши
  • дефисы
  • отсутствие ведущих нулей (при использовании нестрогого режима)

Поведение при частичном совпадении

Moment.js допускает частичное соответствие при нестрогом парсинге. Например:

moment("2026-05", ["YYYY-MM-DD"]);

В этом случае день может быть установлен по умолчанию (обычно 1-е число месяца), если формат допускает недостающие компоненты.

При использовании массива форматов это поведение сохраняется для каждого элемента списка отдельно. Как только находится первый подходящий формат, дальнейшие проверки не выполняются.

Обработка неоднозначных строк

Одним из сложных случаев является работа с датами, которые могут быть интерпретированы несколькими способами:

moment("03/04/2026", ["MM/DD/YYYY", "DD/MM/YYYY"]);

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

При изменении порядка:

moment("03/04/2026", ["DD/MM/YYYY", "MM/DD/YYYY"]);

результат полностью меняется.

Для предотвращения ошибок в таких случаях часто используется явная валидация:

const m = moment("03/04/2026", ["DD/MM/YYYY", "MM/DD/YYYY"], true);

if (!m.isValid()) {
  // обработка ошибки
}

Использование форматов с временем

Массив форматов может включать не только даты, но и комбинации даты и времени:

moment("2026-05-21 14:30", [
  "YYYY-MM-DD HH:mm",
  "DD.MM.YYYY HH:mm",
  "YYYY/MM/DD HH:mm:ss"
]);

Moment.js сопоставляет как дату, так и временные компоненты, включая:

  • часы (HH, hh)
  • минуты (mm)
  • секунды (ss)
  • миллисекунды (SSS)

Отсутствующие элементы могут быть заполнены значениями по умолчанию.

Приоритет форматов и производительность

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

const formats = [
  "YYYY-MM-DD",
  "DD/MM/YYYY",
  "MM-DD-YYYY",
  "YYYY/MM/DD",
  "DD.MM.YYYY",
  "YYYYMMDD"
];

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

Оптимизация достигается за счёт:

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

Взаимодействие с валидацией даты

После парсинга важно учитывать результат функции isValid():

const date = moment("31/02/2026", ["DD/MM/YYYY", "YYYY-MM-DD"]);

date.isValid(); // false

Некорректные даты (например, 31 февраля) могут пройти через синтаксический этап парсинга, но будут отвергнуты на уровне календарной логики.

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

Кастомные форматы и токены

Moment.js использует набор токенов для описания форматов:

  • YYYY — год
  • MM — месяц
  • DD — день
  • HH — часы (24-часовой формат)
  • mm — минуты
  • ss — секунды

Комбинации этих токенов позволяют строить сложные шаблоны:

moment("2026|05|21 14-30", [
  "YYYY|MM|DD HH-mm",
  "YYYY-MM-DD HH:mm"
]);

При работе с несколькими форматами важно соблюдать консистентность токенов, иначе возможны неоднозначные совпадения.

Использование форматов с текстовыми элементами

Moment.js поддерживает форматы, содержащие текстовые вставки:

moment("2026 год 21 мая", [
  "YYYY год DD MMMM",
  "DD MMMM YYYY"
]);

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

moment.locale("ru");

При отсутствии корректной локали сопоставление может не сработать даже при правильной структуре строки.

Сценарии реального применения

Множественные форматы используются в типичных задачах обработки данных:

1. Импорт CSV файлов

moment(value, [
  "YYYY-MM-DD",
  "DD/MM/YYYY",
  "MM/DD/YYYY",
  "YYYYMMDD"
]);

2. Обработка пользовательского ввода

moment(input, [
  "DD.MM.YYYY",
  "D.M.YYYY",
  "YYYY-MM-DD"
]);

3. Интеграция с API разных сервисов

moment(apiDate, [
  moment.ISO_8601,
  "YYYY-MM-DDTHH:mm:ss",
  "YYYY-MM-DD"
]);

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

Особенности поведения при ошибках

Если ни один формат не совпал, Moment.js возвращает невалидный объект:

const m = moment("invalid-date", ["YYYY-MM-DD", "DD/MM/YYYY"]);

m.isValid(); // false

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

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

Сопоставление с текущим временем

При отсутствии входных данных или при частично распознанных форматах возможна подстановка текущей даты:

moment("", ["YYYY-MM-DD"]);

В таких случаях результат зависит от конфигурации и контекста вызова, но чаще всего используется текущее время как fallback.

Использование в цепочках преобразований

После успешного парсинга с несколькими форматами объект Moment.js может быть использован в цепочках:

moment("21-05-2026", ["DD-MM-YYYY", "YYYY/MM/DD"])
  .add(5, "days")
  .format("YYYY-MM-DD");

Множественные форматы влияют только на этап инициализации, не затрагивая дальнейшие операции.

Поведение при локальных настройках

Локаль влияет не только на текстовые месяцы, но и на допустимые варианты парсинга:

moment.locale("fr");

moment("21 mai 2026", [
  "DD MMMM YYYY",
  "YYYY-MM-DD"
]);

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