Начало и конец квартала

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

Календарный год делится на четыре квартала:

  • I квартал: январь — март
  • II квартал: апрель — июнь
  • III квартал: июль — сентябрь
  • IV квартал: октябрь — декабрь

Каждый квартал имеет строго фиксированные границы по месяцам, но переменную длину по дням (от 90 до 92 дней в зависимости от года).

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

  • 0–2 → первый квартал
  • 3–5 → второй квартал
  • 6–8 → третий квартал
  • 9–11 → четвертый квартал

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

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

Основная сигнатура:

import { startOfQuarter } from "date-fns";

startOfQuarter(date);

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

При передаче даты выполняется:

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

Пример

import { startOfQuarter } from "date-fns";

const date = new Date(2026, 5, 18); // 18 июня 2026
const result = startOfQuarter(date);

console.log(result);
// 2026-04-01T00:00:00.000Z (или локальный эквивалент)

Логика вычисления

Для июня (месяц 5) определяется второй квартал:

  • квартал начинается с апреля (месяц 3)
  • дата нормализуется к 1 апреля 00:00:00

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

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

Сигнатура:

import { endOfQuarter } from "date-fns";

endOfQuarter(date);

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

Алгоритм включает:

  • определение последнего месяца квартала
  • переход к последнему дню этого месяца
  • установка времени на 23:59:59.999

Пример

import { endOfQuarter } from "date-fns";

const date = new Date(2026, 5, 18); // июнь 2026
const result = endOfQuarter(date);

console.log(result);
// 2026-06-30T23:59:59.999Z (или локальный эквивалент)

Механика определения границ квартала

Обе функции используют одинаковую базовую модель вычисления:

  1. Получение месяца из даты

  2. Вычисление индекса квартала:

    • Math.floor(month / 3)
  3. Преобразование в границы:

    • начало: quarterIndex * 3
    • конец: (quarterIndex * 3) + 2

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

Для даты 2026-11-10:

  • месяц = 10
  • квартал = Math.floor(10 / 3) = 3
  • начало квартала = 9 (октябрь)
  • конец квартала = 11 (декабрь)

Использование в бизнес-логике

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

Финансовая отчётность

import { startOfQuarter, endOfQuarter } from "date-fns";

function getQuarterRange(date) {
  return {
    start: startOfQuarter(date),
    end: endOfQuarter(date),
  };
}

const range = getQuarterRange(new Date(2026, 10, 3));

console.log(range.start);
console.log(range.end);

Фильтрация данных по кварталу

import { startOfQuarter, endOfQuarter } from "date-fns";

const transactions = [
  { id: 1, date: new Date(2026, 3, 10) },
  { id: 2, date: new Date(2026, 6, 5) },
  { id: 3, date: new Date(2026, 4, 20) },
];

const referenceDate = new Date(2026, 4, 1);

const start = startOfQuarter(referenceDate);
const end = endOfQuarter(referenceDate);

const filtered = transactions.filter(t =>
  t.date >= start && t.date <= end
);

Особенности работы с временем

Функции оперируют объектом Date, что приводит к важным нюансам:

  • локальная временная зона влияет на результат форматирования

  • при сериализации в UTC возможен сдвиг даты

  • время всегда нормализуется:

    • начало квартала → 00:00:00.000
    • конец квартала → 23:59:59.999

Граничные случаи

Переходные даты

Если дата находится на границе квартала:

startOfQuarter(new Date(2026, 3, 1));
endOfQuarter(new Date(2026, 2, 31));

обе функции корректно возвращают один и тот же квартал.

Последний день года

endOfQuarter(new Date(2026, 11, 15));

возвращает 31 декабря текущего года с максимальным временем дня.

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

Операции с кварталами логически связаны с:

  • startOfMonth / endOfMonth
  • startOfYear / endOfYear
  • addQuarters
  • subQuarters

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

Принцип детерминированности вычислений

Любая дата внутри одного и того же квартала всегда даёт одинаковый результат:

startOfQuarter(new Date(2026, 3, 1)) === startOfQuarter(new Date(2026, 5, 30))

Результат одинаков, так как входная дата влияет только на выбор квартала, но не на его границы.

Комбинирование с форматированием

import { startOfQuarter, format } from "date-fns";

const date = new Date(2026, 7, 12);
const start = startOfQuarter(date);

console.log(format(start, "yyyy-MM-dd HH:mm:ss"));

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