Работа с началом и концом недели, месяца, года

Работа с границами недели в JavaScript часто требует учёта локальных стандартов: неделя может начинаться с понедельника или воскресенья, а в некоторых системах используется ISO-неделя, где неделя всегда начинается с понедельника и соответствует международному стандарту.

Библиотека date-fns предоставляет набор функций для вычисления начала и конца недели:

  • startOfWeek(date, options)
  • endOfWeek(date, options)
  • startOfISOWeek(date)
  • endOfISOWeek(date)

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

Функция определения начала недели возвращает дату, установленную на 00:00:00 первого дня недели:

import { startOfWeek } from 'date-fns';

startOfWeek(new Date(2026, 0, 15));

По умолчанию неделя считается начинающейся с воскресенья (0-й день недели в JavaScript-логике). Это поведение может отличаться в зависимости от локали и переданных параметров.

Конец недели определяется аналогично, но устанавливается на 23:59:59.999 последнего дня:

import { endOfWeek } from 'date-fns';

endOfWeek(new Date(2026, 0, 15));

Управление началом недели через options

Ключевым параметром является weekStartsOn, позволяющий задать первый день недели:

import { startOfWeek } from 'date-fns';

startOfWeek(new Date(2026, 0, 15), { weekStartsOn: 1 });

Значения:

  • 0 — воскресенье
  • 1 — понедельник
  • 2 — вторник и так далее

Это позволяет адаптировать расчёты под локальные стандарты календаря.

ISO-неделя

ISO-8601 определяет неделю строго с понедельника. Для этого в date-fns предусмотрены отдельные функции:

import { startOfISOWeek } from 'date-fns';

startOfISOWeek(new Date(2026, 0, 15));

Аналогично:

import { endOfISOWeek } from 'date-fns';

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


Начало и конец месяца

Работа с месяцами в date-fns реализуется через:

  • startOfMonth(date)
  • endOfMonth(date)

Начало месяца

Функция устанавливает дату на первое число месяца с обнулением времени:

import { startOfMonth } from 'date-fns';

startOfMonth(new Date(2026, 4, 22));

Результат всегда соответствует:

  • день: 1
  • время: 00:00:00.000

Конец месяца

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

import { endOfMonth } from 'date-fns';

endOfMonth(new Date(2026, 4, 22));

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

Практическая логика использования границ месяца

Границы месяца часто используются для:

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

При этом важно учитывать, что результат всегда нормализуется до локального времени окружения, в котором выполняется код.


Начало и конец года

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

  • startOfYear(date)
  • endOfYear(date)

Начало года

import { startOfYear } from 'date-fns';

startOfYear(new Date(2026, 6, 10));

Результат фиксируется на:

  • 1 января текущего года
  • 00:00:00.000

Конец года

import { endOfYear } from 'date-fns';

endOfYear(new Date(2026, 6, 10));

Функция возвращает:

  • 31 декабря текущего года
  • 23:59:59.999

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

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

  • годовые отчёты
  • финансовые периоды
  • статистические выборки
  • сравнение периодов год к году

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


Сравнение функций границ времени

Функции date-fns для начала и конца периодов следуют единому принципу:

Период Начало Конец
Неделя startOfWeek endOfWeek
ISO-неделя startOfISOWeek endOfISOWeek
Месяц startOfMonth endOfMonth
Год startOfYear endOfYear

Общая логика:

  • начало периода всегда устанавливает минимальное время (00:00:00.000)
  • конец периода всегда устанавливает максимальное время (23:59:59.999)
  • входная дата используется только как ориентир для выбора периода

Работа с временными зонами и локалью

Хотя date-fns не управляет временными зонами напрямую, поведение границ периодов зависит от локального времени выполнения JavaScript.

При использовании серверных сред или систем с различными таймзонами возникают особенности:

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

Для строгой унификации часто комбинируется date-fns с date-fns-tz, где расчёты переводятся в фиксированную временную зону.


Вложенные периоды и комбинации

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

import { startOfMonth, endOfMonth } from 'date-fns';

const range = {
  start: startOfMonth(new Date()),
  end: endOfMonth(new Date())
};

Аналогично строятся диапазоны:

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

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


Частые ошибки при работе с границами периодов

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

При преобразовании даты в строку (например, JSON) возможна потеря информации о локальном смещении, что приводит к смещению границ периода.

Неверный weekStartsOn

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

  • браузер
  • Node.js
  • локальные настройки сервера

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

Смешивание ISO-недель и локальных недель приводит к расхождению отчётных периодов.


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

Границы периодов часто комбинируются с функциями:

  • isWithinInterval
  • differenceInDays
  • eachDayOfInterval

Пример логики фильтрации:

import { startOfMonth, endOfMonth, isWithinInterval } from 'date-fns';

const interval = {
  start: startOfMonth(new Date()),
  end: endOfMonth(new Date())
};

const result = data.filter(item =>
  isWithinInterval(new Date(item.date), interval)
);

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


Нормализация дат внутри периодов

Все функции startOf* и endOf* приводят дату к строго определённому состоянию:

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

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