Изменение единиц измерения времени

Единицы измерения в timeago.js определяются через систему индексов в функции локали. Каждый индекс соответствует определённому временному интервалу. Пороги переключения между единицами жёстко заданы внутри библиотеки, но поведение можно изменить через кастомные рендеры или постобработку.


Система индексов единиц времени

Функция локали вызывается с аргументом index, определяющим текущую единицу:

index Единица Диапазон разницы
0 прямо сейчас < 45 секунд
1 секунды (ед. ч.) 45–89 секунд
2 секунды (мн. ч.) 89–2700 секунд (45 мин)
3 1 минута 2700–5400 секунд
4 минуты 5400–64800 секунд
5 1 час 64800–129600 секунд
6 часы 129600–77400 секунд
7 1 день ~21.5–35.5 ч
8 дни ~35.5ч–25.5 дней
9 1 неделя ~25.5–45 дней
10 недели
11 1 месяц ~45–319 дней
12 месяцы
13 1 год ~319–547 дней
14 годы > 547 дней

Отображение только нужных единиц

Если требуется скрыть секунды или недели, можно «схлопнуть» соответствующие индексы в ближайшие:

import { register, format } from 'timeago.js';

register('ru_no_seconds', (number, index) => {
  // Индексы 0-2 (секунды) → показываем "только что"
  if (index <= 2) return ['только что', 'скоро'];

  return [
    null,
    null,
    null,
    ['1 минуту назад', 'через 1 минуту'],
    ['%s минут назад', 'через %s минут'],
    ['1 час назад', 'через 1 час'],
    ['%s часов назад', 'через %s часов'],
    ['1 день назад', 'через 1 день'],
    ['%s дней назад', 'через %s дней'],
    ['1 неделю назад', 'через 1 неделю'],
    ['%s недель назад', 'через %s недель'],
    ['1 месяц назад', 'через 1 месяц'],
    ['%s месяцев назад', 'через %s месяцев'],
    ['1 год назад', 'через 1 год'],
    ['%s лет назад', 'через %s лет'],
  ][index];
});

Принудительное использование одной единицы

Если всегда нужно отображать только часы:

register('hours_only', (number, index) => {
  const diff = /* логика расчёта */ 0;

  const hours = Math.round(diff / 3600000);

  if (hours === 0) return ['только что', 'скоро'];
  if (hours === 1) return ['1 час назад', 'через 1 час'];
  return [`${hours} часов назад`, `через ${hours} часов`];
});

Использование дней вместо недель

По умолчанию библиотека переходит на недели после ~25 дней. Чтобы продолжать показывать дни:

register('ru_days_only', (number, index) => {
  // Индексы 9-10 (недели) → переводим в дни
  if (index === 9) return [`${Math.round(number * 7)} дней назад`, `через ${Math.round(number * 7)} дней`];
  if (index === 10) return [`${Math.round(number * 7)} дней назад`, `через ${Math.round(number * 7)} дней`];

  return defaultStrings[index]; // fallback для остальных
});

Кастомный рендер с нестандартными порогами

Для полного контроля над порогами создаётся собственная функция форматирования поверх timeago.js:

import { format } from 'timeago.js';

function customFormat(date, locale = 'ru') {
  const diff = Date.now() - new Date(date).getTime();
  const absSeconds = Math.abs(diff) / 1000;

  if (absSeconds < 3600) {
    // Показывать минуты, даже если timeago перейдёт на часы
    const minutes = Math.round(absSeconds / 60);
    const isPast = diff > 0;
    if (minutes === 0) return 'только что';
    return isPast ? `${minutes} мин. назад` : `через ${minutes} мин.`;
  }

  return format(date, locale);
}

Отображение дней недели для близких дат

import { format } from 'timeago.js';

function smartUnit(date, locale = 'ru') {
  const diff = Date.now() - new Date(date).getTime();
  const days = diff / (1000 * 60 * 60 * 24);

  if (days < 1) return format(date, locale);

  if (days < 7) {
    return new Intl.DateTimeFormat('ru', { weekday: 'long' }).format(new Date(date));
  }

  return new Intl.DateTimeFormat('ru', { day: 'numeric', month: 'long' }).format(new Date(date));
}

Отображение только прошедших дней (без “X месяцев”)

register('ru_max_days', (number, index) => {
  const allInDays = [
    ['только что', 'скоро'],
    ['%s сек. назад', 'через %s сек.'],
    ['%s сек. назад', 'через %s сек.'],
    ['1 мин. назад', 'через 1 мин.'],
    ['%s мин. назад', 'через %s мин.'],
    ['1 ч. назад', 'через 1 ч.'],
    ['%s ч. назад', 'через %s ч.'],
    ['1 д. назад', 'через 1 д.'],
    ['%s д. назад', 'через %s д.'],
    ['%s д. назад', 'через %s д.'], // недели → дни
    ['%s д. назад', 'через %s д.'], // недели
    ['%s д. назад', 'через %s д.'], // месяцы
    ['%s д. назад', 'через %s д.'], // месяцы
    ['%s д. назад', 'через %s д.'], // годы
    ['%s д. назад', 'через %s д.'], // годы
  ];
  return allInDays[index];
});

Динамическая смена единиц по пользовательскому выбору

let preferredUnit = 'auto'; // 'auto' | 'minutes' | 'hours'

function adaptiveFormat(date) {
  if (preferredUnit === 'minutes') {
    const diff = (Date.now() - new Date(date).getTime()) / 60000;
    return `${Math.round(Math.abs(diff))} мин. назад`;
  }

  if (preferredUnit === 'hours') {
    const diff = (Date.now() - new Date(date).getTime()) / 3600000;
    return `${Math.round(Math.abs(diff))} ч. назад`;
  }

  return format(date, 'ru');
}