Парсинг и форматирование дат

Парсинг строковых дат в D3.js опирается на модуль d3-time-format, который реализует разбор и форматирование дат через шаблонные спецификаторы. Основная идея заключается в преобразовании строкового представления времени в объект Date и обратно, с сохранением локальных и временных особенностей.

В основе работы лежит набор директив форматирования, похожих на strftime:

  • %Y — четырёхзначный год
  • %m — месяц (01–12)
  • %d — день месяца
  • %H — часы (00–23)
  • %M — минуты
  • %S — секунды
  • %Z — временная зона
  • %x — локализованная дата
  • %X — локализованное время

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

Парсинг строковых дат

Функция d3.timeParse создаёт парсер на основе шаблона. Результатом работы является функция, преобразующая строку в объект Date.

import { timeParse } from "d3-time-format";

const parseDate = timeParse("%Y-%m-%d");

const date = parseDate("2026-05-16");

Внутренне парсер сопоставляет части строки с указанными позициями шаблона. При несовпадении формат возвращает null, что позволяет контролировать корректность входных данных.

Особенности:

  • строгая привязка к формату;
  • отсутствие автоматического угадывания формата;
  • чувствительность к разделителям;
  • поддержка частичных дат при соответствующем шаблоне.

Форматирование объектов Date

Обратная операция выполняется через d3.timeFormat. Она преобразует объект Date в строку согласно заданному шаблону.

import { timeFormat } from "d3-time-format";

const formatDate = timeFormat("%d.%m.%Y");

const str = formatDate(new Date(2026, 4, 16));

Форматирование всегда опирается на локальное время, если не используется UTC-версия функций.

UTC-парсинг и форматирование

Для работы с универсальным временем используются d3.utcParse и d3.utcFormat. Они идентичны базовым функциям, но интерпретируют дату в UTC-контексте.

import { utcParse, utcFormat } from "d3-time-format";

const parseUTC = utcParse("%Y-%m-%dT%H:%M:%SZ");
const formatUTC = utcFormat("%Y-%m-%dT%H:%M:%SZ");

const d = parseUTC("2026-05-16T12:00:00Z");
const s = formatUTC(d);

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

Локализация форматов

D3 поддерживает создание локализованных парсеров и форматтеров через d3.timeFormatLocale. Это позволяет адаптировать представление даты под конкретные языковые и культурные нормы.

import { timeFormatLocale } from "d3-time-format";

const locale = timeFormatLocale({
  dateTime: "%A, %e %B %Y г. %X",
  date: "%d.%m.%Y",
  time: "%H:%M:%S",
  periods: ["AM", "PM"],
  days: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
  shortDays: ["вс", "пн", "вт", "ср", "чт", "пт", "сб"],
  months: [
    "январь", "февраль", "март", "апрель", "май", "июнь",
    "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"
  ],
  shortMonths: [
    "янв", "фев", "мар", "апр", "май", "июн",
    "июл", "авг", "сен", "окт", "ноя", "дек"
  ]
});

const parse = locale.parse("%d.%m.%Y");
const format = locale.format("%A, %d %B %Y");

const d = parse("16.05.2026");
const s = format(d);

Локализация влияет не только на названия месяцев и дней, но и на правила интерпретации строковых дат.

Использование в масштабах времени (time scale)

Парсинг дат тесно связан с d3.scaleTime, который требует корректных объектов Date на входе.

import { scaleTime } from "d3-scale";

const scale = scaleTime()
  .domain([new Date(2026, 0, 1), new Date(2026, 11, 31)])
  .range([0, 800]);

При работе с данными часто требуется предварительный парсинг строк:

import { timeParse } from "d3-time-format";

const parse = timeParse("%Y-%m-%d");

const data = [
  { date: "2026-01-01", value: 10 },
  { date: "2026-02-01", value: 20 }
];

const parsed = data.map(d => ({
  date: parse(d.date),
  value: d.value
}));

Без такого преобразования временная шкала теряет корректность интерполяции.

Форматирование осей времени

Оси времени в D3 используют форматирование через axisBottom / axisLeft и метод tickFormat.

import { axisBottom } from "d3-axis";
import { timeFormat } from "d3-time-format";

const format = timeFormat("%b %Y");

const axis = axisBottom(scale)
  .tickFormat(format);

Форматирование меток оси должно учитывать плотность данных. Для длинных временных интервалов применяются более укрупнённые форматы:

  • %Y — год
  • %b %Y — месяц и год
  • %d %b — день и месяц
  • %H:%M — время без даты

Автоматическое определение и ограничения

Механизм D3 не выполняет автоматическое распознавание форматов. Каждый парсер жёстко привязан к шаблону.

Это приводит к ряду особенностей:

  • невозможность обработки неоднозначных строк;
  • необходимость нормализации входных данных;
  • зависимость от предсказуемой структуры источника;
  • отсутствие fallback-механизма.

Такая модель повышает производительность и детерминированность обработки.

Работа с неполными датами

При частичном указании компонентов формат может допускать отсутствие некоторых значений:

const parse = timeParse("%Y-%m");

parse("2026-05");

Недостающие поля заполняются значениями по умолчанию (обычно начало периода). Это используется при агрегации данных по месяцам и годам.

Временные интервалы и совместимость

D3 предоставляет временные интервалы (d3-time), которые часто используются вместе с парсингом:

  • timeDay
  • timeMonth
  • timeYear

Парсинг обеспечивает переход от строк к Date, а интервалы — структурирование этих дат в дискретные сегменты.

import { timeMonth } from "d3-time";

timeMonth.floor(new Date(2026, 4, 16));

Такое сочетание применяется при построении агрегированных временных рядов.

Особенности обработки ошибок

При некорректном формате парсер возвращает null, что требует явной обработки:

const parse = timeParse("%Y-%m-%d");

const d = parse("invalid-date");

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

Производительность парсинга

Парсеры, созданные через d3-time-format, компилируются в специализированные функции. Это снижает накладные расходы при массовой обработке данных.

Характерные свойства:

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

При больших наборах данных выгодно создавать парсер один раз и переиспользовать его, а не пересоздавать на каждом элементе.