Работа с ISO-неделями

ISO-недельный календарь основан на стандарте ISO 8601 и отличается от привычного календарного представления тем, как группируются недели и определяется их принадлежность к году. Неделя всегда начинается с понедельника, а первая неделя года — это та, которая содержит первый четверг января (или 4 января). Такая система обеспечивает стабильность нумерации недель между годами и широко используется в бизнес-аналитике, планировании и отчетности.

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


Определение ISO-недели и её границ

Начало и конец ISO-недели

Для получения границ ISO-недели используются функции, которые учитывают смещение относительно понедельника.

Начало ISO-недели:

import { startOfISOWeek } from 'date-fns';

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

Функция возвращает дату понедельника, соответствующего ISO-неделе, в которую входит указанная дата. В отличие от обычного недельного вычисления, здесь всегда фиксирован старт на понедельник вне зависимости от локальных настроек.

Конец ISO-недели:

import { endOfISOWeek } from 'date-fns';

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

Результатом является воскресенье той же ISO-недели с установкой времени на конец дня (23:59:59.999).


Номер ISO-недели

Получение номера недели

ISO-неделя определяется относительно ISO-года, а не календарного года.

import { getISOWeek } from 'date-fns';

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

Результатом будет число от 1 до 53. Некоторые годы содержат 53 недели, что связано с особенностями распределения дней по ISO-правилу.


ISO-год и его отличие от календарного года

Получение ISO-года

ISO-год может не совпадать с календарным годом, особенно для дат в начале января или конце декабря.

import { getISOWeekYear } from 'date-fns';

getISOWeekYear(new Date(2026, 0, 1));

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


Установка ISO-недели

Изменение даты на конкретную ISO-неделю

Функция setISOWeek позволяет сместить дату так, чтобы она оказалась в заданной ISO-неделе текущего ISO-года.

import { setISOWeek } from 'date-fns';

setISOWeek(new Date(2026, 0, 15), 10);

В результате будет возвращена дата, соответствующая той же позиции внутри недели, но перенесённая в 10-ю ISO-неделю.


Установка ISO-года

import { setISOWeekYear } from 'date-fns';

setISOWeekYear(new Date(2026, 0, 15), 2024);

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


Итерация по ISO-неделям

Получение диапазона недель

Для работы с временными промежутками используется генерация последовательности ISO-недель.

import { eachISOWeek } from 'date-fns';

eachISOWeek({
  start: new Date(2026, 0, 1),
  end: new Date(2026, 2, 1),
});

Результатом является массив дат, каждая из которых представляет начало очередной ISO-недели в диапазоне.


Практическая структура ISO-недели

ISO-неделя всегда имеет фиксированную структуру:

  • понедельник — первый день
  • воскресенье — последний день
  • номер недели привязан к ISO-распределению года
  • границы недели не зависят от локализации

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


Согласованность ISO-недель между годами

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

Пример логики:

  • если 1 января приходится на пятницу, субботу или воскресенье — эти дни могут относиться к последней ISO-неделе предыдущего года
  • если 31 декабря приходится на понедельник, вторник или среду — они могут относиться к первой ISO-неделе следующего года

Такая модель устраняет «обрыв» недель между годами.


Совместное использование функций ISO-недель

Часто вычисления строятся на комбинации функций:

import {
  startOfISOWeek,
  endOfISOWeek,
  getISOWeek,
  getISOWeekYear
} from 'date-fns';

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

const start = startOfISOWeek(date);
const end = endOfISOWeek(date);
const weekNumber = getISOWeek(date);
const weekYear = getISOWeekYear(date);

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


Смещение дат внутри ISO-недель

Работа с ISO-неделями часто включает пересчёт дат относительно начала недели.

import { startOfISOWeek, addDays } from 'date-fns';

const monday = startOfISOWeek(new Date(2026, 6, 10));
const thursday = addDays(monday, 3);

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


Типичные ошибки при работе с ISO-неделями

Несоответствие локальному календарю

Некоторые функции JavaScript опираются на воскресенье как начало недели, что конфликтует с ISO-стандартом.

Игнорирование ISO-года

Использование getISOWeek без getISOWeekYear приводит к неоднозначности на границах года.

Смешивание календарных и ISO-функций

Комбинация getWeek и getISOWeek даёт некорректные результаты при переходе между годами.


Сравнение ISO-недельных функций Date-fns

Операция Функция
Начало недели startOfISOWeek
Конец недели endOfISOWeek
Номер недели getISOWeek
ISO-год getISOWeekYear
Установка недели setISOWeek
Установка года setISOWeekYear
Генерация диапазона eachISOWeek

Взаимодействие ISO-недель с форматированием дат

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

import { format, getISOWeek } from 'date-fns';

const date = new Date(2026, 8, 18);

format(date, 'yyyy-MM-dd');
getISOWeek(date);

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


Поведение на границах года

Граничные даты требуют особого внимания:

getISOWeek(new Date(2026, 11, 31));
getISOWeek(new Date(2026, 0, 1));

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


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

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

const key = `${getISOWeekYear(date)}-W${getISOWeek(date)}`;

Такой ключ исключает коллизии между одинаковыми номерами недель в разных годах.


Построение временных сеток на основе ISO-недель

ISO-недели часто становятся базой для сеток планирования:

  • недельные календари
  • спринты в Agile
  • финансовые отчёты
  • аналитика трафика

Последовательное использование eachISOWeek позволяет формировать оси времени без пропусков и дублирования недель.