В JavaScript работа с временными интервалами в рамках международной
локализации опирается на стандартизированные единицы времени,
поддерживаемые спецификациями ECMAScript Internationalization API.
Основной инструмент для отображения относительного времени —
Intl.RelativeTimeFormat, который использует строго
ограниченный набор единиц и правил их языкового преобразования.
В API интернационализации поддерживаются следующие базовые единицы времени:
second — секундаminute — минутаhour — часday — деньweek — неделяmonth — месяцquarter — кварталyear — годКаждая единица представляет собой абстрактный временной интервал, который не привязан к конкретной длительности в миллисекундах. Например, месяц в календарном смысле может иметь 28, 29, 30 или 31 день, что делает прямую арифметику невозможной без контекста календаря.
Intl.RelativeTimeFormat предназначен для форматирования
выражений вида «через 5 минут», «2 дня назад», «через 1 год». Он
принимает числовое значение и одну из поддерживаемых единиц времени.
Базовая структура:
new Intl.RelativeTimeFormat(locales, options)
Пример использования:
const rtf = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
rtf.format(-1, 'day'); // "вчера"
rtf.format(1, 'day'); // "завтра"
rtf.format(-5, 'minute'); // "5 минут назад"
Параметр unit строго ограничен списком поддерживаемых
значений. Попытка использовать произвольные строки (например,
"millisecond" или "decade") приводит к ошибке
или игнорированию в зависимости от окружения.
Важная особенность заключается в том, что единицы интерпретируются лингвистически, а не математически. Это означает, что API не выполняет преобразование между единицами автоматически.
Пример:
rtf.format(60, 'second'); // "через 60 секунд"
rtf.format(1, 'minute'); // "через 1 минуту"
Несмотря на эквивалентность, результат зависит от выбранной единицы.
Intl.RelativeTimeFormat не нормализует значения между
единицами. Разработчик обязан самостоятельно определять, в какой единице
представлять интервал.
Пример ручной нормализации:
const rtf = new Intl.RelativeTimeFormat('ru');
function formatSeconds(value) {
if (value < 60) {
return rtf.format(value, 'second');
}
if (value < 3600) {
return rtf.format(Math.floor(value / 60), 'minute');
}
if (value < 86400) {
return rtf.format(Math.floor(value / 3600), 'hour');
}
return rtf.format(Math.floor(value / 86400), 'day');
}
Такой подход отражает ключевую концепцию: API занимается локализацией, а не вычислением временных интервалов.
Единицы времени в Intl.RelativeTimeFormat подчиняются
правилам множественного числа конкретного языка. Это означает, что одна
и та же числовая величина может иметь разные грамматические формы.
Пример для русского языка:
const rtf = new Intl.RelativeTimeFormat('ru');
rtf.format(-1, 'minute'); // "1 минуту назад"
rtf.format(-2, 'minute'); // "2 минуты назад"
rtf.format(-5, 'minute'); // "5 минут назад"
Система автоматически применяет правила CLDR (Unicode Common Locale Data Repository), исключая необходимость ручной обработки склонений.
Параметр numeric управляет тем, будет ли результат
строго числовым или допускает естественные выражения.
const rtfNumeric = new Intl.RelativeTimeFormat('ru', { numeric: 'always' });
const rtfAuto = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
Примеры:
rtfNumeric.format(-1, 'day'); // "1 день назад"
rtfAuto.format(-1, 'day'); // "вчера"
Для языков с богатыми лексическими формами это существенно влияет на читаемость результата.
Каждая единица времени имеет условный диапазон использования:
second — кратковременные события, таймеры, интервалы
UIminute — пользовательские действия, логированиеhour — расписания, события в течение сутокday — календарные изменения, публикацииweek — аналитика, периодические отчётыmonth — биллинги, подпискиquarter — финансовая отчётностьyear — долгосрочные событияНесмотря на условность, API не накладывает ограничений на диапазон значений внутри каждой единицы.
Некоторые единицы времени не имеют фиксированной длины:
Это приводит к тому, что Intl.RelativeTimeFormat не
оперирует абсолютной длительностью, а лишь обозначает относительную
величину.
Пример:
rtf.format(-1, 'month'); // "1 месяц назад"
rtf.format(1, 'month'); // "через 1 месяц"
Фактическое количество дней не вычисляется.
Современные реализации JavaScript постепенно вводят
Intl.DurationFormat, который дополняет модель единиц
времени более точным представлением длительностей.
Принципиальное отличие заключается в том, что используется набор полей, а не одна единица:
Пример:
const df = new Intl.DurationFormat('ru', { style: 'long' });
df.format({ hours: 2, minutes: 30 });
// "2 часа 30 минут"
В отличие от RelativeTimeFormat, здесь отсутствует
понятие «до/после», акцент делается на длительности.
| Характеристика | RelativeTimeFormat | DurationFormat |
|---|---|---|
| Назначение | Относительное время | Длительность |
| Модель | (value, unit) | объект с полями |
| Направление | есть (прошлое/будущее) | отсутствует |
| Локализация | да | да |
| Примеры | “5 минут назад” | “5 минут 10 секунд” |
Эти два API решают разные задачи и не являются взаимозаменяемыми.
Не все среды поддерживают полный набор единиц или новые API. Наиболее стабильно реализованы:
secondminutehourdaymonthyearМенее универсальны:
weekquarterПри этом поведение может различаться между движками, особенно в старых версиях браузеров.
Выбор единицы времени обычно строится по принципу масштабирования:
Intl.RelativeTimeFormatПример стратегии:
function selectUnit(ms) {
const seconds = Math.abs(ms / 1000);
if (seconds < 60) return ['second', seconds];
if (seconds < 3600) return ['minute', seconds / 60];
if (seconds < 86400) return ['hour', seconds / 3600];
if (seconds < 2592000) return ['day', seconds / 86400];
if (seconds < 31536000) return ['month', seconds / 2592000];
return ['year', seconds / 31536000];
}
Такой подход обеспечивает согласованность отображения независимо от локали.
Разные языки по-разному группируют единицы времени:
API абстрагирует эти различия, оставляя только числовое значение и единицу.
Создание экземпляра Intl.RelativeTimeFormat является
относительно дорогой операцией. В высоконагруженных сценариях
применяется переиспользование:
const rtf = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
function format(value, unit) {
return rtf.format(value, unit);
}
Повторное создание экземпляров на каждый вызов снижает производительность без функциональной необходимости.
Единицы времени в Internationalization API представляют собой фиксированный набор семантических категорий, предназначенных для лингвистического отображения временных интервалов. Их использование отделяет вычислительную часть (нормализацию и выбор масштаба) от языкового представления, что обеспечивает стабильность локализации при изменении языка, региона и культурных правил форматирования времени.