Разбор строковых представлений дат в 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 опирается на три базовых правила:
Эти правила устраняют неоднозначность и защищают от некорректных данных.
Для безопасного парсинга строк, отличных от 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
При строгом режиме:
Любой результат парсинга должен быть проверен:
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 является наиболее надёжным форматом:
dayjs('2026-05-23T10:15:00Z');
Преимущества:
В безопасных системах предпочтение всегда отдаётся 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);
}
Безопасный парсинг не ограничивается получением валидного объекта. Он является первым этапом цепочки обработки данных:
isValid()Каждая из этих ошибок приводит к накоплению скрытых дефектов, которые сложно диагностировать на уровне логики приложения.