В экосистеме FormatJS работа с временем строится вокруг стандарта ICU (International Components for Unicode), где временные интервалы выражаются через абстрактные единицы: секунды, минуты, часы, дни, недели, месяцы и годы. Такая модель позволяет унифицировать локализацию относительного времени и формирование сообщений, зависящих от грамматических правил языка.
Ключевая роль принадлежит Intl.RelativeTimeFormat —
компоненту, отвечающему за преобразование числовых значений и единиц
времени в локализованные строки. В связке с
intl-messageformat и ICU Message Syntax формируется единая
система представления временных данных.
В FormatJS единицы времени задаются строковыми идентификаторами, соответствующими стандарту:
second — секундыminute — минутыhour — часыday — дниweek — неделиmonth — месяцыquarter — кварталыyear — годыКаждая единица интерпретируется не как фиксированное количество секунд, а как семантическая категория, зависящая от локали и правил округления.
Например, «месяц» в одном языке может влиять на падежную систему иначе, чем в другом, даже при одинаковой числовой логике.
Основной механизм FormatJS для работы с единицами времени реализуется
через Intl.RelativeTimeFormat.
Принцип работы основан на паре:
Пример базовой структуры:
const rtf = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
rtf.format(-1, 'day');
rtf.format(1, 'hour');
rtf.format(-5, 'minute');
Каждый вызов преобразует числовую дельту в локализованное выражение относительного времени.
В FormatJS знак числа определяет направление временного сдвига:
| Значение | Единица | Интерпретация |
|---|---|---|
| -1 | day | 1 день назад |
| 1 | day | через 1 день |
| -3 | hour | 3 часа назад |
| 2 | week | через 2 недели |
Такой подход исключает необходимость ручного управления грамматикой прошедшего и будущего времени.
При работе с реальными временными данными часто требуется нормализация значений. FormatJS не выполняет автоматическое преобразование между единицами — ответственность за выбор единицы лежит на уровне бизнес-логики.
Типичные стратегии округления:
Пример нормализации:
function normalize(value, unit) {
if (unit === 'second' && value >= 60) {
return { value: Math.round(value / 60), unit: 'minute' };
}
if (unit === 'minute' && value >= 60) {
return { value: Math.round(value / 60), unit: 'hour' };
}
return { value, unit };
}
В intl-messageformat единицы времени часто используются
внутри ICU-шаблонов, особенно при построении динамических сообщений.
Пример структуры:
const message = new IntlMessageFormat(
'{count, plural, one {# минута назад} few {# минуты назад} many {# минут назад} other {# минут}}',
'ru'
);
Хотя здесь напрямую не используется RelativeTimeFormat,
семантика единиц времени сохраняется через plural rules, которые тесно
связаны с временными интервалами.
Каждая единица времени в FormatJS подчиняется правилам конкретной локали:
Пример различий:
const rtfEn = new Intl.RelativeTimeFormat('en');
const rtfRu = new Intl.RelativeTimeFormat('ru');
rtfEn.format(-1, 'day'); // "1 day ago"
rtfRu.format(-1, 'day'); // "1 день назад"
Даже при одинаковой единице day результат зависит от
морфологии языка.
Единицы времени можно условно разделить на две категории:
Характеризуются высокой изменчивостью и используются в интерфейсах реального времени: чаты, уведомления, логи.
Используются в аналитике, календарях, архивных данных.
При проектировании временных сообщений важна консистентность единиц. FormatJS предоставляет только механизм форматирования, но не определяет контекст выбора единицы.
Типичная стратегия выбора:
30 дней → months/years
Параметр numeric в RelativeTimeFormat
влияет на стиль вывода:
numeric: "always" — всегда числовая формаnumeric: "auto" — допускает словесные формыПример:
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
rtf.format(-1, 'day'); // "yesterday"
rtf.format(1, 'day'); // "tomorrow"
rtf.format(-2, 'day'); // "2 days ago"
Автоматические формы зависят от поддержки локали и набора правил ICU.
Несмотря на фиксированный набор стандартных единиц, в прикладной логике часто вводятся абстракции:
FormatJS не интерпретирует такие единицы напрямую, но допускает их маппинг к базовым:
const mapUnit = (unit) => {
switch (unit) {
case 'business-day': return 'day';
case 'fiscal-quarter': return 'quarter';
default: return unit;
}
};
При накоплении времени возникает задача каскадного преобразования:
FormatJS не выполняет подобные операции, однако структура единиц времени в ICU предполагает возможность внешнего расчёта и последующего форматирования только финального результата.
Единицы времени тесно связаны с системой множественного числа ICU:
В языках с развитой морфологией (например, славянские языки) корректное отображение зависит от категории числа, а не только от самого значения.
Граничные значения (0, 1, -1) имеют особое значение:
Пример:
const rtf = new Intl.RelativeTimeFormat('en');
rtf.format(0, 'day'); // "in 0 days"
Некоторые локали переопределяют поведение нуля через
numeric: "auto".
В системах на FormatJS единицы времени обычно отделены от слоя сообщений:
RelativeTimeFormatТакая декомпозиция позволяет изолировать бизнес-логику от языковой модели ICU и обеспечивает предсказуемость форматирования в многоязычных приложениях.