Пороговые значения — это временны́е границы, по которым библиотека решает, какую единицу времени использовать. По умолчанию они жёстко закодированы внутри timeago.js и не поддаются настройке через публичное API. Тем не менее существуют паттерны, позволяющие переопределить поведение с нужными порогами.
Внутри timeago.js используется таблица порогов для определения индекса:
const SEC = 1000;
const MIN = SEC * 60;
const HOUR = MIN * 60;
const DAY = HOUR * 24;
const WEEK = DAY * 7;
const MON = DAY * 30;
const YEAR = DAY * 365;
// Упрощённая таблица внутри библиотеки:
[
[0.7 * MIN, 0], // < 45c → "только что"
[1.5 * MIN, 1], // < 90c → "1 минуту"
[45 * MIN, 2], // < 45м → "X минут"
[1.5 * HOUR, 3], // < 90м → "1 час"
[22 * HOUR, 4], // < 22ч → "X часов"
[36 * HOUR, 5], // < 36ч → "1 день"
[26 * DAY, 6], // < 26д → "X дней"
[46 * DAY, 7], // < 46д → "1 месяц"
[320 * DAY, 8], // < 320д → "X месяцев"
[548 * DAY, 9], // < 548д → "1 год"
[Infinity, 10], // иначе → "X лет"
]
Поскольку пороги нельзя изменить через API, создаётся собственный форматтер с нужными порогами:
const THRESHOLDS = [
[30 * 1000, 0, 0], // < 30с → "только что"
[90 * 1000, 1, 1], // < 90с → "секунды"
[60 * 60 * 1000, 2, 60], // < 1ч → минуты
[24 * 60 * 60 * 1000, 3, 3600], // < 1д → часы
[Infinity, 4, 86400], // иначе → дни
];
const LABELS_RU = [
['только что', 'скоро'],
['%s сек. назад', 'через %s сек.'],
['%s мин. назад', 'через %s мин.'],
['%s ч. назад', 'через %s ч.'],
['%s д. назад', 'через %s д.'],
];
function customFormat(date) {
const diff = new Date(date).getTime() - Date.now();
const abs = Math.abs(diff);
const isPast = diff < 0;
for (const [threshold, index, divisor] of THRESHOLDS) {
if (abs < threshold) {
const count = divisor ? Math.round(abs / (divisor * 1000)) : 0;
const [past, future] = LABELS_RU[index];
const template = isPast ? past : future;
return template.replace('%s', count);
}
}
}
По умолчанию “только что” показывается до 45 секунд. Если нужно расширить до 2 минут:
import { register, format } from 'timeago.js';
register('ru_wide_now', (number, index) => {
// Для индексов 0 (сейчас), 1 (секунды) и частично 2 — показывать "только что"
if (index <= 2) return ['только что', 'скоро'];
return standardRuStrings[index];
});
timeago.js переходит с дней на недели примерно на 26-м дне. Чтобы продолжать показывать дни:
register('ru_nodweeks', (number, index) => {
// Недели (индексы 9-10) заменяем на дни
const adjustedIndex = (index === 9 || index === 10) ? 8 : index;
const adjustedNumber = (index === 9) ? number * 7 : number;
return ruStrings(adjustedNumber, adjustedIndex);
});
register('ru_daywords', (number, index) => {
if (index === 7 && number === 1) return ['вчера', 'завтра'];
if (index === 8 && number === 2) return ['позавчера', 'послезавтра'];
return ruStrings(number, index);
});
В некоторых UI секунды не нужны — показываются только минуты:
function formatForFeed(date) {
const diff = Date.now() - new Date(date).getTime();
const MINUTE = 60 * 1000;
if (diff < MINUTE) {
return 'только что';
}
return format(date, 'ru');
}
let minThreshold = 60000; // 1 минута по умолчанию
function setMinThreshold(ms) {
minThreshold = ms;
}
function thresholdFormat(date) {
const diff = Date.now() - new Date(date).getTime();
if (diff < minThreshold) {
return 'только что';
}
return format(date, 'ru');
}
// Установить порог в 5 минут
setMinThreshold(5 * 60 * 1000);
Для дат старше N дней показывать абсолютную дату:
import { format } from 'timeago.js';
const MAX_RELATIVE_DAYS = 30;
function smartDate(date, locale = 'ru') {
const ageMs = Date.now() - new Date(date).getTime();
const ageDays = ageMs / (1000 * 60 * 60 * 24);
if (ageDays > MAX_RELATIVE_DAYS) {
return new Intl.DateTimeFormat(locale, {
day: 'numeric',
month: 'long',
year: 'numeric',
}).format(new Date(date));
}
return format(date, locale);
}
function futureFormat(date, locale = 'ru') {
const diff = new Date(date).getTime() - Date.now();
if (diff <= 0) return 'прошло';
if (diff < 60000) return 'через несколько секунд';
return format(date, locale);
}
На мобильных устройствах можно использовать более сжатые пороги:
const isMobile = window.innerWidth < 768;
function deviceAdaptiveFormat(date) {
return format(date, isMobile ? 'ru_short' : 'ru');
}
При этом 'ru_short' — кастомная локаль с сокращёнными
строками.