Сравнение по кварталам

Работа с кварталами в JavaScript через date-fns строится на наборе функций, которые позволяют определять принадлежность даты к кварталу, вычислять границы кварталов и выполнять арифметические операции с квартальными интервалами. Квартальная модель календаря используется в финансовой отчётности, аналитике, планировании релизов и агрегации временных данных, где год разбивается на четыре равные части по три месяца.

Квартал определяется как трёхмесячный интервал:

  • 1 квартал: январь — март
  • 2 квартал: апрель — июнь
  • 3 квартал: июль — сентябрь
  • 4 квартал: октябрь — декабрь

Функция getQuarter(date) возвращает номер квартала для переданной даты.

import { getQuarter } from 'date-fns';

getQuarter(new Date(2026, 0, 15)); // 1
getQuarter(new Date(2026, 6, 1));  // 3
getQuarter(new Date(2026, 11, 31)); // 4

Логика вычисления основана на номере месяца: январь имеет индекс 0, поэтому квартал определяется как Math.floor(month / 3) + 1.

Сравнение дат по принадлежности к одному кварталу

Функция isSameQuarter(dateLeft, dateRight) используется для проверки того, находятся ли две даты в одном квартале одного года.

import { isSameQuarter } from 'date-fns';

isSameQuarter(
  new Date(2026, 1, 10),
  new Date(2026, 2, 25)
); // true

isSameQuarter(
  new Date(2026, 2, 31),
  new Date(2026, 3, 1)
); // false

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

isSameQuarter(
  new Date(2025, 0, 1),
  new Date(2026, 1, 1)
); // false

Границы квартала: начало и конец интервала

Для задач агрегации и построения отчётов используются функции startOfQuarter и endOfQuarter.

Начало квартала

startOfQuarter(date) возвращает дату, установленную на первый день первого месяца квартала с нулевым временем.

import { startOfQuarter } from 'date-fns';

startOfQuarter(new Date(2026, 5, 20));
// 2026-04-01T00:00:00.000Z (или локальное время)

Конец квартала

endOfQuarter(date) возвращает последний момент последнего дня квартала.

import { endOfQuarter } from 'date-fns';

endOfQuarter(new Date(2026, 5, 20));
// 2026-06-30T23:59:59.999Z (или локальное время)

Эти функции используются для формирования диапазонов:

const start = startOfQuarter(new Date(2026, 5, 20));
const end = endOfQuarter(new Date(2026, 5, 20));

const interval = { start, end };

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

Разница между кварталами

Функция differenceInQuarters(dateLeft, dateRight) вычисляет разницу в количестве полных кварталов между двумя датами.

import { differenceInQuarters } from 'date-fns';

differenceInQuarters(
  new Date(2026, 9, 1),
  new Date(2026, 0, 1)
); // 3

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

Поведение функции:

  • учитываются только завершённые кварталы
  • дробные кварталы отбрасываются
  • направление влияет на знак результата
differenceInQuarters(
  new Date(2026, 0, 1),
  new Date(2026, 9, 1)
); // -3

Сдвиг дат по кварталам

Для смещения даты на определённое количество кварталов используется addQuarters.

import { addQuarters } from 'date-fns';

addQuarters(new Date(2026, 0, 15), 1);
// 2026-04-15

addQuarters(new Date(2026, 0, 15), -2);
// 2025-07-15

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

Аналогично используется subQuarters:

import { subQuarters } from 'date-fns';

subQuarters(new Date(2026, 6, 10), 1);
// 2026-03-10

Проверка принадлежности к диапазону квартала

Комбинация startOfQuarter и endOfQuarter позволяет выполнять проверку попадания даты в текущий квартал.

import { isWithinInterval, startOfQuarter, endOfQuarter } from 'date-fns';

const date = new Date(2026, 4, 15);

isWithinInterval(date, {
  start: startOfQuarter(date),
  end: endOfQuarter(date)
}); // true

Такая проверка используется в аналитических выборках и построении квартальных отчётов.

Индексация кварталов в бизнес-логике

В реальных системах нумерация кварталов часто используется как ключ группировки данных:

const data = [
  { date: new Date(2026, 0, 10), value: 100 },
  { date: new Date(2026, 3, 5), value: 200 },
  { date: new Date(2026, 6, 15), value: 300 },
];

const grouped = data.reduce((acc, item) => {
  const year = item.date.getFullYear();
  const quarter = getQuarter(item.date);
  const key = `${year}-Q${quarter}`;

  if (!acc[key]) acc[key] = 0;
  acc[key] += item.value;

  return acc;
}, {});

Результат:

2026-Q1 → 100
2026-Q2 → 200
2026-Q3 → 300

Работа с переходами между кварталами

Кварталы не требуют ручного расчёта месяцев при переходах. Все операции основаны на календарной модели:

  • переход Q4 → Q1 следующего года происходит автоматически
  • отрицательные сдвиги корректно уменьшают год
  • дни внутри месяца сохраняются
addQuarters(new Date(2026, 10, 30), 2);
// переход в следующий год с корректировкой месяца

Особенности и крайние случаи

Разные длины месяцев

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

Временные зоны

Функции работают с объектами Date, поэтому поведение зависит от локальной временной зоны окружения исполнения.

Пограничные даты

Даты на границе кварталов строго относятся к одному из интервалов:

isSameQuarter(new Date(2026, 2, 31), new Date(2026, 3, 1));
// false

Март 31 и апрель 1 относятся к разным кварталам, несмотря на близость по времени.

Использование в аналитических расчётах

Квартальная модель часто применяется для:

  • финансовых отчётов (выручка Q1–Q4)
  • планирования релизов
  • сравнения периодов роста
  • агрегации статистики

Типовой паттерн включает три операции:

  • определение квартала: getQuarter
  • нормализация границ: startOfQuarter, endOfQuarter
  • сравнение или разница: isSameQuarter, differenceInQuarters

Эта комбинация формирует основу работы с квартальными данными без необходимости ручного календарного расчёта