Работа с датами в JavaScript традиционно делится на две отдельные
задачи: форматирование и интерпретация строк. Встроенный
Intl API предоставляет мощные инструменты для
локализованного отображения дат, но обратное преобразование — парсинг
уже отформатированной строки обратно в структурированные компоненты — не
имеет прямого универсального решения.
Основная причина заключается в том, что форматирование зависит от локали, пользовательских настроек и конкретных правил представления даты. Одна и та же дата может выглядеть по-разному:
26.05.2026 (ru-RU)05/26/2026 (en-US)2026-05-26 (ISO-подобный формат)26 mai 2026 (fr-FR)Стандарт ECMAScript не предоставляет метода вида
Intl.DateTimeFormat.parse(), поэтому обратное
преобразование строится через косвенные механизмы.
Базовый инструмент для локализованного вывода дат —
Intl.DateTimeFormat:
const formatter = new Intl.DateTimeFormat('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
formatter.format(new Date(2026, 4, 26)); // "26.05.2026"
Этот API работает только в одну сторону: из Date →
строка.
Однако для задач парсинга критически важен метод:
formatToParts()
Метод formatToParts() возвращает структуру, а не строку.
Вместо единого текста он выдаёт массив компонентов:
const formatter = new Intl.DateTimeFormat('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
formatter.formatToParts(new Date(2026, 4, 26));
Результат:
[
{ type: 'day', value: '26' },
{ type: 'literal', value: '.' },
{ type: 'month', value: '05' },
{ type: 'literal', value: '.' },
{ type: 'year', value: '2026' }
]
Эта структура является ключом к обратному преобразованию, поскольку:
type: 'day', 'month', 'year'
содержат смысловые данныеliteral описывает разделители и формат локалиПарсинг форматированной даты обычно строится в два шага:
formatToParts()function getFormatStructure(locale, options) {
const dtf = new Intl.DateTimeFormat(locale, options);
const parts = dtf.formatToParts(new Date(2000, 0, 2));
return parts.map(p => ({
type: p.type,
value: p.value
}));
}
Использование фиксированной даты позволяет определить порядок компонентов.
На основе структуры можно создать регулярное выражение:
function buildDateParser(locale) {
const dtf = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
const sample = dtf.formatToParts(new Date(2000, 0, 2));
let pattern = '';
const map = [];
for (const part of sample) {
if (part.type === 'year') {
pattern += '(\\d{4})';
map.push('year');
} else if (part.type === 'month') {
pattern += '(\\d{1,2})';
map.push('month');
} else if (part.type === 'day') {
pattern += '(\\d{1,2})';
map.push('day');
} else {
pattern += part.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
}
const regex = new RegExp(`^${pattern}$`);
return function parse(dateString) {
const match = dateString.match(regex);
if (!match) return null;
const result = {};
map.forEach((key, index) => {
result[key] = Number(match[index + 1]);
});
return result;
};
}
Пример использования:
const parseRU = buildDateParser('ru-RU');
parseRU('26.05.2026');
// { day: 26, month: 5, year: 2026 }
Главная сложность парсинга через Intl заключается в
отсутствии стабильного формата. Даже внутри одной локали могут
изменяться:
. / -
)Например:
new Intl.DateTimeFormat('en-GB').format(new Date(2026, 4, 26));
// "26/05/2026"
new Intl.DateTimeFormat('en-US').format(new Date(2026, 4, 26));
// "5/26/2026"
Это делает невозможным использование фиксированных шаблонов без предварительного анализа.
Если используется текстовое представление месяца:
const fmt = new Intl.DateTimeFormat('en-US', {
month: 'long',
day: 'numeric',
year: 'numeric'
});
пример строки:
May 26, 2026
formatToParts():
[
{ type: 'month', value: 'May' },
{ type: 'literal', value: ' ' },
{ type: 'day', value: '26' },
{ type: 'literal', value: ', ' },
{ type: 'year', value: '2026' }
]
Парсинг требует дополнительной нормализации:
Пример словаря:
const monthMap = {
January: 0,
February: 1,
March: 2,
April: 3,
May: 4,
June: 5,
July: 6,
August: 7,
September: 8,
October: 9,
November: 10,
December: 11
};
Более устойчивый подход основан на разборе массива частей:
function parseByParts(locale, dateString) {
const dtf = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
const skeleton = dtf.formatToParts(new Date(2000, 0, 2));
const input = dtf.formatToParts(new Date(dateString));
const result = {};
for (let i = 0; i < skeleton.length; i++) {
const s = skeleton[i];
const v = input[i];
if (s.type === 'year') result.year = Number(v.value);
if (s.type === 'month') result.month = Number(v.value);
if (s.type === 'day') result.day = Number(v.value);
}
return result;
}
Этот метод работает только при строгом соответствии формата, но избегает регулярных выражений и уменьшает зависимость от символов-разделителей.
Использование Intl для обратного преобразования имеет
фундаментальные ограничения:
Нет стандартизированного метода интерпретации строк дат.
Операционная система и браузер могут менять формат вывода.
Одна локаль может возвращать:
Некоторые форматы неоднозначны:
05/06/2026
В реальных приложениях часто комбинируются разные стратегии:
new Date().toISOString();
Плюсы:
Хотя задача рассматривается через Intl, на практике
часто используются:
Новый стандарт ECMAScript предоставляет более структурированную работу с датами и временем, включая более явные механизмы разбора, но его поддержка пока не универсальна.
Комбинация formatToParts() и словарей даёт наиболее
устойчивую модель:
function createIntlDateParser(locale) {
const dtf = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
return function parse(str) {
const parts = dtf.formatToParts(new Date(str));
const result = {};
for (const p of parts) {
if (p.type === 'year') result.year = Number(p.value);
if (p.type === 'month') result.month = Number(p.value);
if (p.type === 'day') result.day = Number(p.value);
}
return result;
};
}
Такая модель опирается на совпадение локализованного формата и входной строки, что делает её пригодной только для строго контролируемых условий.
На уровне архитектуры систем обработки дат выделяются три слоя:
Нормализация входа
Локализация вывода
Intl.DateTimeFormatformatToParts для анализа структурыХранилище
Такой подход минимизирует необходимость сложного обратного парсинга
локализованных строк, оставляя Intl в роли исключительно
форматирующего слоя