Ограничение диапазона дат

По умолчанию timeago.js форматирует любые даты без ограничений — от нескольких секунд до десятков лет. Однако в реальных приложениях часто нужно ограничить диапазон: показывать относительное время только для свежих дат, а для старых — абсолютное.


Ограничение снизу: не показывать будущее

import { format } from 'timeago.js';

function pastOnly(date, locale = 'ru') {
  if (new Date(date).getTime() > Date.now()) {
    return 'скоро';
  }
  return format(date, locale);
}

Ограничение сверху: переключение на абсолютный формат

import { format } from 'timeago.js';

const MAX_RELATIVE_MS = 7 * 24 * 60 * 60 * 1000; // 7 дней

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

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

  return format(date, locale);
}

Вывод:

5 минут назад          ← относительное
26 мая 2025 г.         ← абсолютное для дат старше 7 дней

Ограничение по минимуму

Не показывать “только что” если дата старше 1 минуты:

import { format } from 'timeago.js';

function minOneMinute(date, locale = 'ru') {
  const diff = Date.now() - new Date(date).getTime();

  if (diff < 60000) {
    return 'только что';
  }

  return format(date, locale);
}

Пороговые уровни: комбинация диапазонов

import { format } from 'timeago.js';

const RANGES = [
  { max: 30 * 1000,                label: () => 'только что' },
  { max: 24 * 60 * 60 * 1000,      label: (d) => format(d, 'ru') },
  { max: 7 * 24 * 60 * 60 * 1000,  label: (d) => `${Math.round((Date.now() - new Date(d).getTime()) / 86400000)} дн. назад` },
  { max: Infinity,                  label: (d) => new Intl.DateTimeFormat('ru', { day: 'numeric', month: 'long', year: 'numeric' }).format(new Date(d)) },
];

function rangedFormat(date) {
  const diff = Date.now() - new Date(date).getTime();
  for (const range of RANGES) {
    if (diff < range.max) return range.label(date);
  }
}

Ограничение для будущих дат с дедлайнами

import { format } from 'timeago.js';

function deadlineFormat(date, locale = 'ru') {
  const diff = new Date(date).getTime() - Date.now();

  if (diff < 0) {
    return 'просрочено';
  }

  if (diff < 60000) {
    return 'менее минуты';
  }

  if (diff > 30 * 24 * 60 * 60 * 1000) {
    return new Intl.DateTimeFormat('ru', {
      day:   'numeric',
      month: 'long',
    }).format(new Date(date));
  }

  return format(date, locale);
}

Ограничение для ленты новостей (максимум 30 дней)

import { format } from 'timeago.js';

function feedFormat(date) {
  const ageMs = Date.now() - new Date(date).getTime();
  const ageDays = ageMs / (1000 * 60 * 60 * 24);

  if (ageDays > 30) {
    return new Intl.DateTimeFormat('ru', {
      day:   'numeric',
      month: 'short',
      year:  'numeric',
    }).format(new Date(date));
  }

  return format(date, 'ru');
}

Конфигурируемая функция с диапазоном

import { format } from 'timeago.js';

function createFormatter({ maxRelativeMs = Infinity, minRelativeMs = 0, locale = 'ru' } = {}) {
  return function(date) {
    const diff = Math.abs(Date.now() - new Date(date).getTime());

    if (diff < minRelativeMs) {
      return 'только что';
    }

    if (diff > maxRelativeMs) {
      return new Intl.DateTimeFormat(locale, {
        dateStyle: 'medium',
      }).format(new Date(date));
    }

    return format(date, locale);
  };
}

const formatPost = createFormatter({ maxRelativeMs: 7 * 24 * 60 * 60 * 1000, locale: 'ru' });
const formatComment = createFormatter({ maxRelativeMs: 24 * 60 * 60 * 1000, locale: 'ru' });

Ограничение с fallback-строкой

import { format } from 'timeago.js';

function formatWithFallback(date, fallback = 'давно', locale = 'ru') {
  const MAX = 365 * 24 * 60 * 60 * 1000; // 1 год
  const diff = Math.abs(Date.now() - new Date(date).getTime());

  if (diff > MAX) return fallback;

  return format(date, locale);
}

Применение в React-компоненте

import { format } from 'timeago.js';

const MAX_DAYS = 30;

function PostDate({ date }: { date: string }) {
  const ageMs   = Date.now() - new Date(date).getTime();
  const ageDays = ageMs / (1000 * 60 * 60 * 24);

  if (ageDays > MAX_DAYS) {
    return (
      <time dateTime={date}>
        {new Intl.DateTimeFormat('ru', { dateStyle: 'long' }).format(new Date(date))}
      </time>
    );
  }

  return (
    <time dateTime={date}>
      {format(date, 'ru')}
    </time>
  );
}