Безопасный парсинг

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

Библиотека Day.js решает часть этих проблем за счёт предсказуемого API, строгих правил парсинга и расширяемой системы плагинов. Однако даже при её использовании остаётся задача безопасного разбора входных данных, особенно когда строки дат приходят извне: из форм, API или URL-параметров.

Официальный сайт библиотеки: Day.js


Базовый разбор строк и его ограничения

Стандартный вызов:

import dayjs from 'dayjs';

const d = dayjs('2026-05-23');

Поддерживает ISO-формат, но становится проблемным при других входных данных:

dayjs('23/05/2026'); // может быть некорректно интерпретировано
dayjs('05-23-2026'); // неоднозначность формата (MM-DD vs DD-MM)

Ключевая проблема — отсутствие строгого контракта на входной формат. Day.js по умолчанию старается “угадать” дату, что в контексте безопасности парсинга считается нежелательным поведением.


Принцип безопасного парсинга

Безопасный парсинг в контексте Day.js опирается на три базовых правила:

  1. Явное указание формата входной строки
  2. Использование строгого режима разбора
  3. Проверка валидности результата

Эти правила устраняют неоднозначность и защищают от некорректных данных.


Плагин customParseFormat как основа строгого разбора

Для безопасного парсинга строк, отличных от ISO 8601, используется плагин customParseFormat.

import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';

dayjs.extend(customParseFormat);

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

const d = dayjs('23/05/2026', 'DD/MM/YYYY', true);

Третий аргумент true включает строгий режим.


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

Строгий режим — ключевой элемент безопасного разбора.

dayjs('2026-13-01', 'YYYY-MM-DD', true); // invalid
dayjs('2026-12-01', 'YYYY-MM-DD', true); // valid

При строгом режиме:

  • запрещены отклонения от формата
  • не допускаются “догадки” библиотеки
  • отклоняются некорректные даты (например, 32 число месяца)

Проверка валидности результата

Любой результат парсинга должен быть проверен:

const date = dayjs('31/02/2026', 'DD/MM/YYYY', true);

if (!date.isValid()) {
  throw new Error('Некорректная дата');
}

Метод isValid() — обязательный элемент безопасной обработки входных данных.


Опасные сценарии при отсутствии строгого парсинга

Без строгого режима возможны скрытые ошибки:

dayjs('2026-02-31'); // "перепрыгивает" в март
dayjs('2026-00-10'); // интерпретируется непредсказуемо

Такие значения могут проходить валидацию бизнес-логики, если проверка отсутствует, что приводит к:

  • ошибкам в расписаниях
  • неверным дедлайнам
  • некорректным финансовым расчётам

Безопасный разбор пользовательского ввода

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

function parseUserDate(input) {
  const date = dayjs(input, 'DD.MM.YYYY', true);

  if (!date.isValid()) {
    return null;
  }

  return date;
}

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


Нормализация входных форматов

Часто данные приходят в разных форматах. В этом случае важно не пытаться “угадать”, а нормализовать вход:

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

function parseFlexible(input) {
  for (const format of formats) {
    const d = dayjs(input, format, true);
    if (d.isValid()) return d;
  }
  return null;
}

Такой подход сохраняет безопасность за счёт строгой проверки каждого варианта.


Работа с ISO 8601 как безопасным стандартом

ISO 8601 является наиболее надёжным форматом:

dayjs('2026-05-23T10:15:00Z');

Преимущества:

  • отсутствие двусмысленности
  • одинаковая интерпретация в любых окружениях
  • корректная работа с UTC

В безопасных системах предпочтение всегда отдаётся ISO как внутреннему формату хранения.


Таймзоны и влияние на корректность парсинга

Без учета временных зон возможны ошибки интерпретации даты.

Для расширенной работы используется плагин utc и timezone:

import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

dayjs.extend(utc);
dayjs.extend(timezone);

Пример безопасного разбора:

const d = dayjs.tz('2026-05-23 10:00', 'Europe/Moscow');

При отсутствии явной зоны дата может быть смещена относительно ожидаемого времени.


Защита от инъекций через строки дат

Хотя строки дат не являются классической точкой SQL-инъекций, они могут стать источником логических уязвимостей:

  • обход фильтров диапазона дат
  • подмена временных окон
  • некорректные отчёты

Пример опасного сценария:

if (dayjs(userInput).isAfter(dayjs('2026-01-01'))) {
  // логика допуска
}

Если userInput не проверен, любое некорректное значение может привести к неожиданным результатам.


Рекомендованный безопасный паттерн обработки

Комплексный подход включает:

import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';

dayjs.extend(customParseFormat);

function safeParseDate(input) {
  if (typeof input !== 'string') return null;

  const date = dayjs(input, 'DD-MM-YYYY', true);

  if (!date.isValid()) return null;

  return date;
}

Дополнительные уровни защиты:

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

Валидация диапазонов после парсинга

Даже корректно разобранная дата требует проверки бизнес-ограничений:

const min = dayjs('2000-01-01');
const max = dayjs('2030-12-31');

function validateRange(date) {
  return date.isAfter(min) && date.isBefore(max);
}

Комбинирование парсинга и бизнес-логики

Безопасный парсинг не ограничивается получением валидного объекта. Он является первым этапом цепочки обработки данных:

  1. Строгий разбор строки
  2. Проверка валидности
  3. Проверка диапазона
  4. Преобразование в бизнес-формат
  5. Использование в логике приложения

Типичные ошибки при использовании Day.js в парсинге

  • отсутствие явного формата
  • игнорирование isValid()
  • смешивание локальных и UTC дат без контроля
  • доверие пользовательскому вводу
  • использование нестрогого режима в критичных системах

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