Валидация пользовательского ввода

Работа с пользовательским вводом дат в приложениях на JavaScript требует строгого контроля корректности данных, поскольку любая неоднозначность в формате даты приводит к логическим ошибкам, сбоям фильтрации и некорректным вычислениям. В экосистеме JavaScript одной из наиболее удобных библиотек для обработки дат выступает Day.js, предоставляющая лаконичный API и предсказуемое поведение при парсинге и валидации.


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

  • разные форматы (2026-01-24, 24/01/2026, Jan 24 2026)
  • неполные значения (24-01, 01/2026)
  • ошибочные строки (32/13/2026, abcd)
  • локальные особенности записи даты

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


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

В Day.js базовая валидация строится вокруг функции dayjs() и метода isValid().

Основной принцип

Любая строка преобразуется в объект даты:

import dayjs from 'dayjs';

const date = dayjs('2026-01-24');

console.log(date.isValid()); // true

При невозможности интерпретации строки объект считается невалидным:

const date = dayjs('invalid-date');

console.log(date.isValid()); // false

Поведение парсера по умолчанию

Стандартный парсер Day.js:

  • поддерживает ISO 8601
  • допускает «мягкий» разбор строки
  • может интерпретировать неоднозначные форматы

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


Строгая валидация форматов

Для строгого контроля используется плагин customParseFormat.

Подключение

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

dayjs.extend(customParseFormat);

Строгий разбор строки

const date = dayjs('24/01/2026', 'DD/MM/YYYY', true);

console.log(date.isValid()); // true

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

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

Пример отклонения некорректных данных

dayjs('24-01-2026', 'DD/MM/YYYY', true).isValid(); // false
dayjs('32/01/2026', 'DD/MM/YYYY', true).isValid(); // false

Нормализация пользовательского ввода

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

Удаление лишних символов

function normalizeInput(input) {
  return input.trim().replace(/\s+/g, ' ');
}

Унификация разделителей

function normalizeDateString(input) {
  return input
    .trim()
    .replace(/\./g, '/')
    .replace(/-/g, '/');
}

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


Проверка нескольких форматов

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

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

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

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


Проверка диапазонов дат

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

Минимальная и максимальная дата

const minDate = dayjs('2000-01-01');
const maxDate = dayjs('2030-12-31');

function isInRange(date) {
  return date.isAfter(minDate) && date.isBefore(maxDate);
}

Включительные границы

function isInRangeInclusive(date) {
  return (
    (date.isAfter(minDate) || date.isSame(minDate)) &&
    (date.isBefore(maxDate) || date.isSame(maxDate))
  );
}

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

Некоторые значения формально соответствуют формату, но логически невозможны:

  • 31 февраля
  • 30 апреля 31 числа
  • 29 февраля в не високосный год

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

dayjs('31/02/2026', 'DD/MM/YYYY', true).isValid(); // false

При этом в нестрогом режиме возможны неожиданные «перепрыгивания» дат, что требует осторожности.


Работа с временными зонами

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

Подключение UTC-плагина

import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);

Нормализация в UTC

const date = dayjs.utc('2026-01-24T10:00:00');

console.log(date.isValid());

Использование UTC позволяет избежать:

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

Валидация на уровне форм

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

Пример логики проверки

function validateDateInput(value) {
  const parsed = dayjs(value, 'DD/MM/YYYY', true);

  if (!parsed.isValid()) {
    return { valid: false, error: 'Некорректный формат даты' };
  }

  if (!isInRange(parsed)) {
    return { valid: false, error: 'Дата вне допустимого диапазона' };
  }

  return { valid: true, date: parsed };
}

Такой подход разделяет:

  • синтаксическую валидацию
  • семантическую проверку
  • бизнес-ограничения

Проверка частично введённых значений

При интерактивном вводе (маски ввода) данные могут быть неполными:

  • 24/01
  • 2026-01

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

function isPotentialDate(input) {
  return /^[0-9/.-]+$/.test(input);
}

Это позволяет различать:

  • потенциально корректный ввод
  • полностью некорректные строки

Типичные ошибки при валидации

1. Доверие нестрогому парсингу

dayjs('2026-13-40') // может дать неожиданный результат без проверки

2. Отсутствие isValid()

Объект Day.js всегда создаётся, но не всегда содержит корректную дату.

3. Игнорирование форматов

dayjs('24/01/2026') // интерпретация зависит от окружения

4. Смешивание локального времени и UTC

Сравнение дат без нормализации приводит к смещению логики.


Сравнение стратегий валидации

Мягкая валидация

  • допускает разные форматы
  • удобна для UX
  • менее надёжна

Строгая валидация

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

Гибридный подход

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

Интеграция с серверной частью

При передаче даты на сервер необходимо:

  • отправлять нормализованный формат (обычно ISO)
  • не полагаться на локальные форматы
  • повторно валидировать входные данные
const payload = {
  date: parsed.toISOString()
};

Валидация в цепочках обработки данных

При работе с массивами дат часто используется фильтрация:

const validDates = inputs
  .map(v => dayjs(v, 'DD/MM/YYYY', true))
  .filter(d => d.isValid());

Это позволяет очистить данные перед дальнейшей обработкой.


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

Перед сравнением всегда требуется проверка корректности:

if (a.isValid() && b.isValid()) {
  console.log(a.isBefore(b));
}

Без этого сравнение может давать некорректные результаты даже при создании объекта из ошибочной строки.


Стратегия устойчивой валидации

Комбинированный подход к обработке пользовательского ввода обычно включает:

  • нормализацию строки
  • строгий парсинг через customParseFormat
  • проверку isValid()
  • контроль диапазона
  • унификацию временной зоны
  • серверную повторную проверку

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