Метод formatRangeToParts

Метод formatRangeToParts расширяет возможности форматирования дат в рамках API интернационализации, предоставляя структурированное представление результата форматирования диапазона дат. В отличие от formatRange, который возвращает строку, данный метод возвращает массив частей, каждая из которых описывает отдельный сегмент итогового отображения: числа, разделители, названия месяцев, временные зоны и другие элементы.

Основная цель метода — обеспечить точный контроль над тем, как именно интернационализированная строка диапазона дат разбивается на логические компоненты, пригодные для кастомного рендеринга интерфейсов.


Сигнатура метода

Intl.DateTimeFormat.prototype.formatRangeToParts(startDate, endDate)

Параметры

  • startDate — начальная дата диапазона (объект Date или значение, приводимое к нему)
  • endDate — конечная дата диапазона (объект Date или значение, приводимое к нему)

Возвращаемое значение

Возвращается массив объектов, где каждый объект имеет структуру:

{
  type: string,
  value: string,
  source: "startRange" | "endRange" | "shared"
}

Структура возвращаемых частей

Каждый элемент результата представляет отдельный фрагмент форматированного диапазона.

Поле type

Определяет роль части:

  • year — год
  • month — месяц
  • day — день
  • hour — час
  • minute — минуты
  • second — секунды
  • literal — разделители (например, «.», «/», «–»)
  • timeZoneName — название временной зоны
  • weekday — день недели
  • era — эра

Поле value

Строковое представление части, уже локализованное согласно выбранной локали.

Поле source

Указывает происхождение части:

  • startRange — часть относится к начальной дате
  • endRange — часть относится к конечной дате
  • shared — часть общая для обеих дат и не дублируется

Базовое поведение

При форматировании диапазона дат движок стремится:

  1. Выделить общие части (например, год или месяц)
  2. Сократить дублирование информации
  3. Разделить уникальные элементы начала и конца диапазона

Например, диапазон внутри одного месяца может отображать общий месяц только один раз.


Пример использования

const formatter = new Intl.DateTimeFormat("ru-RU", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const parts = formatter.formatRangeToParts(
  new Date(2024, 0, 1),
  new Date(2024, 0, 10)
);

console.log(parts);

Результат может быть представлен примерно так:

[
  { type: "day", value: "1", source: "startRange" },
  { type: "literal", value: "–", source: "shared" },
  { type: "day", value: "10", source: "endRange" },
  { type: "month", value: "января", source: "shared" },
  { type: "year", value: "2024", source: "shared" }
]

Отличие от formatRange

Метод formatRange возвращает готовую строку:

"1–10 января 2024"

Метод formatRangeToParts возвращает структурированный результат, который позволяет:

  • изменять порядок отображения элементов
  • добавлять собственную разметку
  • стилизовать части отдельно
  • интегрировать с UI-фреймворками

Принцип работы локализации

Формирование частей полностью зависит от настроек Intl.DateTimeFormat, включая:

  • locale
  • timeZone
  • calendar
  • dateStyle
  • timeStyle
  • дополнительные параметры (year, month, day и т.д.)

Например, при смене локали изменяются не только значения, но и порядок частей:

new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long", day: "numeric" })

и

new Intl.DateTimeFormat("de-DE", { year: "numeric", month: "long", day: "numeric" })

дадут разные последовательности частей, даже при одинаковых датах.


Работа с временными диапазонами

При использовании времени поведение расширяется за счёт дополнительных токенов:

  • hour
  • minute
  • second
  • timeZoneName

Пример:

const formatter = new Intl.DateTimeFormat("en-GB", {
  hour: "2-digit",
  minute: "2-digit"
});

formatter.formatRangeToParts(
  new Date(2024, 0, 1, 10, 0),
  new Date(2024, 0, 1, 12, 30)
);

Результат будет содержать разделённые части времени с возможными общими компонентами даты.


Оптимизация повторяющихся элементов

Одной из ключевых особенностей является автоматическое подавление дублирования.

Если диапазон:

  • находится в одном году
  • в одном месяце
  • в одной временной зоне

то эти части помечаются как shared и не повторяются.

Пример логики:

  • начало: 1 января 2024
  • конец: 10 января 2024

Год и месяц будут shared, день — разделён.


Использование в пользовательском интерфейсе

Структура результата позволяет строить гибкие шаблоны отображения.

Каждый элемент можно:

  • оборачивать в HTML-теги
  • стилизовать отдельно
  • переставлять в DOM-структуре

Пример логики рендеринга:

parts.map(part => {
  if (part.type === "literal") return part.value;
  return `<span class="${part.type}">${part.value}</span>`;
}).join("");

Особенности поведения с границами диапазона

При переходах между:

  • месяцами
  • годами
  • часовыми поясами

структура частей меняется:

  • общие части могут исчезать из startRange/endRange и становиться shared
  • порядок частей может перестраиваться
  • разделители (literal) могут меняться в зависимости от локали

Поддержка календарей

В зависимости от calendar в Intl, форматирование может использовать:

  • григорианский календарь (по умолчанию)
  • исламский календарь
  • японские эры
  • буддийский календарь

Каждый календарь влияет на:

  • era
  • year
  • локализацию месяцев и дней

Сравнение с formatToParts

Метод formatToParts работает с одной датой, а formatRangeToParts — с диапазоном.

Ключевое различие:

  • formatToParts(date) — разбор одной точки времени
  • formatRangeToParts(start, end) — разбор интервала с логикой объединения и различения частей

Типичные сценарии обработки результата

Построение кастомных таймлайнов

Части позволяют визуально выделять начало и конец диапазона.

Интернационализированные календарные компоненты

Используется для построения календарей с поддержкой разных языков без ручного форматирования.

Точная стилизация дат

Каждый компонент может иметь собственный стиль, зависящий от type.


Поведение при одинаковых датах

Если startDate и endDate совпадают:

  • результат эквивалентен formatToParts
  • диапазонная логика сокращается до одной точки
  • source может содержать только shared и элементы одной стороны

Обработка некорректных значений

Если переданы некорректные даты:

  • значения приводятся к Date
  • при невозможности приведения возникает RangeError

Пример:

formatter.formatRangeToParts("invalid", new Date());

может привести к исключению в зависимости от реализации движка.


Влияние параметров форматирования

Параметры Intl.DateTimeFormat напрямую влияют на разбиение:

  • dateStyle: "full" увеличивает количество частей (добавляется weekday)
  • timeStyle: "short" сокращает набор временных компонентов
  • hourCycle влияет на формат часов
  • timeZone изменяет timeZoneName и смещает значения времени

Стабильность структуры

Несмотря на гибкость локализации, структура parts сохраняет:

  • предсказуемый порядок внутри одной локали
  • согласованность между вызовами при одинаковых параметрах
  • стабильные значения type для семантических компонентов

Однако порядок между разными локалями не фиксирован и зависит от правил конкретного языка и региона.