getISOWeek для ISO-недель

ISO-неделя — это система нумерации недель года, стандартизированная ISO 8601. В отличие от «обычного» календарного подхода, где неделя начинается с 1 января и может иметь произвольное смещение, ISO-недели подчиняются строгим правилам:

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

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

Например:

  • 1 января может быть частью ISO-недели 52 или 53 предыдущего года
  • 31 декабря может относиться к ISO-неделе 1 следующего года

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


Функция getISOWeek

В библиотеке date-fns функция getISOWeek предназначена для вычисления номера ISO-недели для заданной даты.

Она возвращает число от 1 до 52 (иногда до 53), соответствующее ISO-неделе года, к которой относится дата.

Сигнатура

getISOWeek(date)
  • date — объект Date или временная метка
  • возвращаемое значение — number (номер ISO-недели)

Базовый принцип работы

Функция опирается на стандартизированное правило ISO:

  1. Определяется ISO-год даты
  2. Вычисляется первая ISO-неделя этого года
  3. Определяется смещение даты относительно начала ISO-недельной системы
  4. Результат выражается в количестве полных недель

Ключевой момент: расчёт не зависит от локальных настроек календаря (например, первого дня недели в стране).


Примеры использования

Простое определение недели

import { getISOWeek } from 'date-fns';

const date = new Date(2024, 0, 10); // 10 января 2024
const week = getISOWeek(date);

console.log(week);

Если дата попадает во вторую или третью неделю января, результат будет соответствующим ISO-структуре, а не календарному смещению.


Граница года

import { getISOWeek } from 'date-fns';

const date = new Date(2020, 11, 31); // 31 декабря 2020
const week = getISOWeek(date);

console.log(week);

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


Переход через новый год

import { getISOWeek } from 'date-fns';

console.log(getISOWeek(new Date(2021, 11, 27))); // декабрь 2021
console.log(getISOWeek(new Date(2022, 0, 3)));   // январь 2022

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


Отличие от getWeek

В date-fns существует также функция getWeek, которая выглядит похожей, но имеет принципиальные отличия:

Функция Основа расчёта Гибкость Стандарт
getWeek локальные настройки высокая нет
getISOWeek ISO 8601 фиксированная да

Ключевые различия

  • getISOWeek всегда считает недели по ISO-правилам
  • getWeek зависит от параметров options.weekStartsOn и options.firstWeekContainsDate
  • getISOWeek гарантирует совместимость между системами и странами

Внутренние особенности вычисления

Алгоритм ISO-нумерации включает несколько шагов:

1. Нормализация даты

Дата приводится к UTC-подобному виду для исключения влияния часового пояса.

2. Определение четверга текущей недели

ISO-неделя всегда «якорится» на четверге. Это связано с правилом определения первой недели года.

3. Поиск начала ISO-года

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

4. Вычисление разницы недель

Количество недель между началом ISO-года и текущей датой формирует результат.


Особенности ISO-недельного календаря

Возможность 53-й недели

Некоторые годы содержат 53 недели вместо 52. Это происходит, если:

  • год начинается в четверг, или
  • високосный год начинается в среду

В таких случаях декабрь «растягивается» на дополнительную неделю.


Разрыв между календарным и ISO-годом

Пример ситуации:

  • 30 декабря 2019 может принадлежать ISO-2020
  • 1 января 2021 может принадлежать ISO-2020

Таким образом, ISO-неделя не привязана строго к границам календарного года.


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

Логирование и аналитика

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

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

Финансовые системы

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

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

Планирование задач

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


Типичные ошибки при использовании

Ошибка 1: ожидание совпадения с календарной неделей

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


Ошибка 2: игнорирование переходных дат

Даты в начале января и конце декабря часто относятся к «чужому» ISO-году, что приводит к некорректной группировке данных.


Ошибка 3: смешивание getWeek и getISOWeek

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


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

getISOWeek часто используется вместе с:

  • startOfISOWeek — начало ISO-недели
  • endOfISOWeek — конец ISO-недели
  • getISOWeekYear — ISO-год даты
  • setISOWeek — установка номера недели

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


Влияние временных зон

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

Особенности:

  • дата 00:30 может относиться к предыдущему дню в UTC
  • переходы DST не влияют на номер недели
  • расчёт стабилен при любых временных смещениях

Поведение на краевых значениях

Минимально возможная дата

getISOWeek(new Date(1970, 0, 1))

Результат зависит от того, в какую ISO-неделю попадает начало эпохи Unix.


Очень далёкие даты

Алгоритм сохраняет корректность для исторических и будущих дат, так как основан на математическом расчёте недель относительно ISO-якоря, а не на календарных таблицах.


Производительность

getISOWeek относится к лёгким операциям:

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

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


Использование в массовой обработке

import { getISOWeek } from 'date-fns';

const dates = [
  new Date(2024, 0, 1),
  new Date(2024, 0, 8),
  new Date(2024, 0, 15),
];

const weeks = dates.map(getISOWeek);

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


Взаимосвязь ISO-недели и бизнес-логики

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

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

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