Механизм относительного форматирования времени в Intl
реализован через Intl.RelativeTimeFormat. Он предназначен
для преобразования числовых временных интервалов в локализованные
человекочитаемые строки: «2 часа назад», «через 5 дней», «в прошлом
месяце». В отличие от ручной сборки строк, данный API учитывает правила
языка, падежи, множественные формы и региональные особенности.
Экземпляр форматтера создаётся один раз и переиспользуется:
const rtf = new Intl.RelativeTimeFormat("ru", {
numeric: "auto",
style: "long"
});
Конструктор Intl.RelativeTimeFormat принимает локаль и
объект настроек.
new Intl.RelativeTimeFormat(locales, options);
Локаль определяет языковые правила форматирования:
new Intl.RelativeTimeFormat("ru");
new Intl.RelativeTimeFormat("en-US");
new Intl.RelativeTimeFormat("kk");
При отсутствии явного указания используется локаль среды выполнения.
style управляет длиной и формой результата.
"long" — полная форма: «через 3 минуты»"short" — сокращённая форма: «через 3 мин.»"narrow" — максимально компактная: «+3 мин»new Intl.RelativeTimeFormat("ru", { style: "short" });
Компактные формы особенно полезны в интерфейсах с ограниченным пространством, например, в таблицах или уведомлениях.
numeric контролирует, будет ли результат строго
числовым.
"always" — всегда используется число"auto" — допускаются естественные выраженияnew Intl.RelativeTimeFormat("ru", { numeric: "auto" });
При numeric: "auto" возможны языковые замены:
При numeric: "always" результат остаётся числовым:
Метод format(value, unit) принимает числовое значение и
единицу измерения.
Поддерживаемые единицы:
"second""minute""hour""day""week""month""quarter""year"rtf.format(-5, "minute"); // "5 минут назад"
rtf.format(2, "hour"); // "через 2 часа"
Знак числа определяет направление:
Метод format возвращает строку с учётом локали:
const rtf = new Intl.RelativeTimeFormat("ru");
rtf.format(-1, "day"); // "1 день назад"
rtf.format(3, "day"); // "через 3 дня"
rtf.format(-2, "hour"); // "2 часа назад"
Для английской локали:
const rtfEn = new Intl.RelativeTimeFormat("en");
rtfEn.format(-1, "day"); // "1 day ago"
rtfEn.format(2, "day"); // "in 2 days"
Метод formatToParts возвращает структурированное
представление результата.
const rtf = new Intl.RelativeTimeFormat("ru");
rtf.formatToParts(-2, "hour");
Результат:
[
{ type: "integer", value: "2", unit: "hour" },
{ type: "literal", value: " часа назад" }
]
Этот формат используется при построении интерфейсов, где требуется стилизация отдельных частей строки.
Относительное форматирование опирается на CLDR-правила языка. Это означает, что:
Пример для русского языка:
rtf.format(-1, "day"); // "1 день назад"
rtf.format(-2, "day"); // "2 дня назад"
rtf.format(-5, "day"); // "5 дней назад"
Одна и та же операция может давать разные результаты в зависимости от языка:
const ru = new Intl.RelativeTimeFormat("ru");
const kk = new Intl.RelativeTimeFormat("kk");
const en = new Intl.RelativeTimeFormat("en");
ru.format(-1, "hour"); // "1 час назад"
en.format(-1, "hour"); // "1 hour ago"
kk.format(-1, "hour"); // зависит от реализации локали
Локализация затрагивает не только слова, но и структуру выражения.
Относительное форматирование используется в интерфейсах, где важна динамическая временная привязка:
Пример вычисления интервала:
const rtf = new Intl.RelativeTimeFormat("ru");
function formatTimeAgo(date) {
const diff = Date.now() - date.getTime();
const minutes = Math.round(diff / 60000);
return rtf.format(-minutes, "minute");
}
Корректный выбор unit критичен для читаемости результата. Обычно применяется нормализация:
Пример нормализации:
function getUnit(seconds) {
if (seconds < 60) return "second";
if (seconds < 3600) return "minute";
if (seconds < 86400) return "hour";
if (seconds < 604800) return "day";
return "week";
}
Создание Intl.RelativeTimeFormat является относительно
дорогой операцией. В высоконагруженных сценариях экземпляры обычно
кэшируются:
const cache = new Map();
function getFormatter(locale) {
if (!cache.has(locale)) {
cache.set(locale, new Intl.RelativeTimeFormat(locale));
}
return cache.get(locale);
}
Это снижает накладные расходы при массовом форматировании.
Разделение на части позволяет стилизовать числовое значение отдельно от текста:
const parts = rtf.formatToParts(-10, "minute");
Пример использования:
Режим "auto" позволяет избегать избыточной числовой
информации:
const rtf = new Intl.RelativeTimeFormat("ru", {
numeric: "auto"
});
rtf.format(-1, "day"); // "вчера"
rtf.format(0, "day"); // "сегодня"
rtf.format(1, "day"); // "завтра"
При более сложных значениях (например, -2, +3) используется числовая форма.
Часто используется совместно с Date и временными
вычислениями:
const rtf = new Intl.RelativeTimeFormat("ru");
const diffMs = targetDate - new Date();
const diffDays = Math.round(diffMs / 86400000);
rtf.format(diffDays, "day");
Такой подход позволяет строить универсальные функции отображения времени без привязки к конкретному языку.