Операции с кварталами

В работе с календарными данными кварталы используются как укрупнённая единица временной агрегации, позволяющая группировать даты по финансовым, аналитическим и отчётным периодам. В экосистеме date-fns операции с кварталами реализованы как набор чистых функций, не изменяющих исходные объекты Date, что обеспечивает предсказуемость и удобство композиции.

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

  • Q1: январь — март
  • Q2: апрель — июнь
  • Q3: июль — сентябрь
  • Q4: октябрь — декабрь

Базовая особенность реализации заключается в том, что все вычисления опираются на локальное время экземпляра Date, без скрытых преобразований состояния.


Определение квартала: getQuarter

Функция определения квартала возвращает число от 1 до 4, соответствующее текущему кварталу даты.

import { getQuarter } from 'date-fns'

getQuarter(new Date(2024, 0, 15)) // 1
getQuarter(new Date(2024, 4, 10)) // 2
getQuarter(new Date(2024, 8, 1))  // 3
getQuarter(new Date(2024, 11, 31)) // 4

Механика вычисления

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

quarter = Math.floor(month / 3) + 1

где month — значение от 0 до 11.


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

Функция возвращает дату, приведённую к первому моменту первого дня квартала.

import { startOfQuarter } from 'date-fns'

startOfQuarter(new Date(2024, 5, 20))
// 2024-04-01T00:00:00.000

Особенности поведения

  • устанавливается 1 число месяца
  • время сбрасывается в 00:00:00.000
  • месяц нормализуется к началу квартала

Пример вычисления

Для месяца m:

startMonth = Math.floor(m / 3) * 3

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

Функция возвращает последнюю миллисекунду последнего дня квартала.

import { endOfQuarter } from 'date-fns'

endOfQuarter(new Date(2024, 5, 20))
// 2024-06-30T23:59:59.999

Характеристика результата

  • учитывается реальная длина месяца (28–31 день)
  • устанавливается максимальное время дня
  • корректно работает на границах года

Арифметика кварталов: addQuarters и subQuarters

Операции смещения по кварталам реализуют сдвиг на 3 месяца за единицу.

Добавление кварталов

import { addQuarters } from 'date-fns'

addQuarters(new Date(2024, 0, 10), 1)
// 2024-04-10

Добавление нескольких кварталов:

addQuarters(new Date(2024, 0, 10), 3)
// 2024-10-10

Вычитание кварталов

import { subQuarters } from 'date-fns'

subQuarters(new Date(2024, 6, 15), 1)
// 2024-03-15

Особенности смещения

  • сохраняется день месяца при возможности
  • при переполнении месяца происходит корректировка (например, 31 января → апрель корректируется к 30 апреля)
  • переход года обрабатывается автоматически

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

Функция вычисляет целое количество кварталов между двумя датами.

import { differenceInQuarters } from 'date-fns'

differenceInQuarters(
  new Date(2024, 9, 1),
  new Date(2024, 0, 1)
) // 3

Принцип расчёта

  1. вычисляется разница в месяцах
  2. результат делится на 3
  3. округление происходит в сторону нуля

Формально:

diff = (monthA - monthB) / 3

Установка квартала: setQuarter

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

import { setQuarter } from 'date-fns'

setQuarter(new Date(2024, 0, 15), 3)
// 2024-07-15

Правила трансформации

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

Граничные случаи календаря

Переход года

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

addQuarters(new Date(2024, 10, 10), 1)
// 2025-02-10

Конец месяца

При работе с датами 29–31 числа возможна коррекция:

addQuarters(new Date(2024, 0, 31), 1)
// 2024-04-30

Причина — отсутствие 31 числа в апреле.


Использование кварталов в агрегации данных

Квартальная группировка часто применяется в аналитических задачах.

Определение ключа группировки

import { getQuarter } from 'date-fns'

function getQuarterKey(date) {
  return `${date.getFullYear()}-Q${getQuarter(date)}`
}

Результаты:

  • 2024-Q1
  • 2024-Q2
  • 2024-Q3

Приведение массива дат к кварталам

const grouped = dates.reduce((acc, date) => {
  const key = `${date.getFullYear()}-Q${getQuarter(date)}`
  acc[key] = acc[key] || []
  acc[key].push(date)
  return acc
}, {})

Сценарии финансового моделирования

Квартальные операции часто используются в финансовой отчётности:

  • построение P&L по периодам
  • анализ выручки
  • планирование бюджетов
  • прогнозирование трендов

Пример построения отчётного окна

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

function getReportingWindow(date) {
  return {
    from: startOfQuarter(date),
    to: endOfQuarter(date)
  }
}

Взаимодействие с другими функциями date-fns

Квартальные операции часто комбинируются с:

  • startOfYear, endOfYear
  • addMonths, subMonths
  • format
  • isWithinInterval

Пример фильтрации диапазона

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

function filterByQuarter(dates, date) {
  const interval = {
    start: startOfQuarter(date),
    end: endOfQuarter(date)
  }

  return dates.filter(d => isWithinInterval(d, interval))
}

Особенности реализации и производительность

Функции кварталов в date-fns построены на следующих принципах:

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

Каждая операция имеет сложность O(1) и не зависит от размера данных, что делает их пригодными для высоконагруженных вычислений временных рядов.