Date и Intl: интернационализация

Date — встроенный объект JavaScript для работы с датами и временем; Intl — API интернационализации для форматирования чисел, дат, строк в соответствии с локалью пользователя.

Зачем нужно

Без Intl форматирование дат и чисел требовало бы ручного кода или тяжёлых библиотек (Moment.js, day.js). Современный Intl встроен в браузер и Node.js и покрывает 95% задач: локализованные даты, валюты, числа, относительное время («3 часа назад»), сортировку строк по локали. Date — основа для работы с временными метками, хотя его API неудобен для сложных манипуляций.

Где используется

  • Форматирование дат в интерфейсе: «10 апреля 2026» вместо 2026-04-10
  • Валюта и числа: 1 500,00 ₽ или $1,500.00 в зависимости от локали
  • Относительное время: «3 минуты назад», «через 2 дня» через Intl.RelativeTimeFormat
  • Сортировка строк с учётом языка: Intl.Collator для правильного порядка кириллицы
  • Пагинация дат: вычисление разницы, добавление дней/месяцев

Основной контент

Date — создание и основные операции

// Создание
const now = new Date();
const specific = new Date('2026-04-10'); // ISO 8601
const byParts = new Date(2026, 3, 10);   // Внимание: месяц 0-based!
const fromTimestamp = new Date(1712707200000);

// Получение компонентов (локальное время)
now.getFullYear();    // 2026
now.getMonth();       // 0-11 (январь = 0!)
now.getDate();        // 1-31
now.getDay();         // 0-6 (воскресенье = 0)
now.getHours();       // 0-23
now.getMinutes();     // 0-59

// UTC-версии
now.getUTCFullYear;
now.getUTCHours;

// Временная метка
now.getTime(); // миллисекунды с 1970-01-01 UTC
Date.now();    // то же без создания объекта (производительнее)

// Вычисление разницы в днях
function daysBetween(a, b) {
  return Math.round(Math.abs(b - a) / (1000 * 60 * 60 * 24));
}

// Добавление дней
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

Intl.DateTimeFormat — локализованное форматирование дат

const date = new Date('2026-04-10T14:30:00');

// Базовое форматирование
new Intl.DateTimeFormat('ru-RU').format(date); // '10.04.2026'
new Intl.DateTimeFormat('en-US').format(date); // '4/10/2026'
new Intl.DateTimeFormat('de-DE').format(date); // '10.4.2026'

// Детальный контроль
new Intl.DateTimeFormat('ru-RU', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  weekday: 'long',
  hour: '2-digit',
  minute: '2-digit'
}).format(date);
// 'пятница, 10 апреля 2026 г., 14:30'

// Переиспользуемый форматтер
const dateFormatter = new Intl.DateTimeFormat('ru-RU', {
  year: 'numeric', month: 'short', day: 'numeric'
});
dates.map(d => dateFormatter.format(new Date(d)));

Intl.NumberFormat — числа и валюта

// Числа
new Intl.NumberFormat('ru-RU').format(1500000);       // '1 500 000'
new Intl.NumberFormat('en-US').format(1500000);       // '1,500,000'

// Валюта
new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
}).format(1500.5); // '1 500,50 ₽'

new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(1500.5); // '$1,500.50'

// Проценты
new Intl.NumberFormat('ru-RU', {
  style: 'percent',
  minimumFractionDigits: 1
}).format(0.1567); // '15,7%'

// Компактный формат
new Intl.NumberFormat('ru-RU', { notation: 'compact' }).format(1500000); // '1,5 млн'

Intl.RelativeTimeFormat — относительное время

const rtf = new Intl.RelativeTimeFormat('ru-RU', { numeric: 'auto' });

rtf.format(-1, 'day');    // 'вчера'
rtf.format(1, 'day');     // 'завтра'
rtf.format(-3, 'hour');   // '3 часа назад'
rtf.format(2, 'week');    // 'через 2 недели'
rtf.format(-30, 'second'); // '30 секунд назад'

// Утилита «N единиц назад»
function timeAgo(date) {
  const seconds = Math.floor((Date.now() - date) / 1000);
  const units = [
    [60, 'second'], [3600, 'minute'], [86400, 'hour'],
    [604800, 'day'], [2592000, 'week'], [31536000, 'month']
  ];
  for (const [limit, unit] of units) {
    if (seconds < limit) {
      return rtf.format(-Math.floor(seconds / (limit / 60)), unit);
    }
  }
  return rtf.format(-Math.floor(seconds / 31536000), 'year');
}

Частые ошибки

  • Месяц 0-based: new Date(2026, 3, 10) — это 10 апреля (3 = апрель), а не 10 марта.
  • Мутация Date: setDate, setMonth изменяют объект на месте — при вычислениях создавайте копию через new Date(original).
  • Создание форматтера в цикле: new Intl.DateTimeFormat(...) дорого создавать. Выносите за пределы циклов.
  • Парсинг строк дат: new Date('2026-04-10') интерпретирует как UTC полночь, а new Date('2026-04-10T00:00:00') — как локальное время. Разница в часовом поясе может дать другой день.

Связанные темы

Ресурсы