Настройка пороговых значений

Пороговые значения — это временны́е границы, по которым библиотека решает, какую единицу времени использовать. По умолчанию они жёстко закодированы внутри 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' — кастомная локаль с сокращёнными строками.