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

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

В Day.js работа с ISO-неделями реализуется через плагин isoWeek, который добавляет методы для вычисления номера недели, ISO-года и дня недели в стандартизированном формате.


Подключение и активация ISO-недель

Функциональность ISO-недель не входит в базовую сборку Day.js и подключается отдельно:

import dayjs from 'dayjs'
import isoWeek from 'dayjs/plugin/isoWeek'

dayjs.extend(isoWeek)

После расширения экземпляры Day.js получают дополнительные методы и корректную логику вычисления недель по стандарту ISO 8601.


Отличие ISO-недель от стандартных недель

В Day.js существует два подхода к определению недели:

  • локальная неделя (locale week) — зависит от настроек локали и может начинаться с воскресенья или понедельника

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

    • неделя начинается с понедельника
    • неделя 1 содержит 4 января (или первый четверг года)
    • неделя всегда имеет 7 дней

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


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

Метод isoWeek() возвращает номер недели в ISO-формате:

dayjs('2026-01-01').isoWeek()

Результат зависит от календарной структуры года и может отличаться от стандартного week().

Сравнение:

dayjs('2026-01-01').week()     // локальная неделя
dayjs('2026-01-01').isoWeek()  // ISO-неделя

Разница особенно заметна в первых и последних днях года.


ISO-неделя года (ISO week-year)

ISO-неделя может относиться к году, отличному от календарного. Для этого используется метод:

dayjs('2026-01-01').isoWeekYear()

Этот метод возвращает ISO-год, который может отличаться от year().

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

dayjs('2020-12-31').year()        // 2020
dayjs('2020-12-31').isoWeekYear() // 2021

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


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

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

dayjs().isoWeek(10)

Это изменяет текущую дату, смещая её к указанной ISO-неделе текущего ISO-года.


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

Метод isoWeekday() работает в диапазоне от 1 до 7:

  • 1 — понедельник
  • 7 — воскресенье
dayjs().isoWeekday(1) // понедельник
dayjs().isoWeekday(7) // воскресенье

Также возможно получение текущего дня недели:

dayjs('2026-05-22').isoWeekday()

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

Day.js позволяет работать с границами недели через startOf и endOf:

dayjs().startOf('isoWeek')
dayjs().endOf('isoWeek')

Результаты:

  • начало недели — понедельник 00:00:00
  • конец недели — воскресенье 23:59:59.999

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


Форматирование ISO-недель

Для отображения недель в строках используется форматирование через format().

Номер недели

dayjs().format('WW')

WW — двухзначный номер недели (с ведущим нулём).


ISO год и неделя

Day.js поддерживает специальные токены:

  • GGGG — ISO год
  • WW — ISO неделя
dayjs().format('GGGG-[W]WW')

Пример результата:

2026-W21

Практика расчёта диапазонов ISO-недель

Типичный сценарий — получение диапазона дат недели:

const start = dayjs('2026-05-22').startOf('isoWeek')
const end = dayjs('2026-05-22').endOf('isoWeek')

start.format('YYYY-MM-DD')
end.format('YYYY-MM-DD')

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


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

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

const data = [
  { date: '2026-01-02', value: 10 },
  { date: '2026-01-03', value: 20 },
  { date: '2026-01-10', value: 15 }
]

const grouped = {}

data.forEach(item => {
  const key = dayjs(item.date).format('GGGG-[W]WW')

  if (!grouped[key]) {
    grouped[key] = []
  }

  grouped[key].push(item)
})

Результатом становится структура, сгруппированная по ISO-неделям, что удобно для отчётности и построения графиков.


Корректность переходов между годами

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

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

Пример проверки:

dayjs('2019-12-31').format('GGGG-[W]WW')
dayjs('2020-01-01').format('GGGG-[W]WW')

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


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

Плагин isoWeek игнорирует локальные настройки начала недели. Даже если локаль определяет воскресенье как начало недели, ISO-логика остаётся неизменной.

Это обеспечивает:

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

Использование ISO-недель в вычислениях диапазонов дат

Расчёт предыдущей и следующей недели:

const current = dayjs()

const prev = current.subtract(1, 'week').startOf('isoWeek')
const next = current.add(1, 'week').startOf('isoWeek')

Такая модель применяется в календарях, расписаниях и системах планирования.


Связь ISO-недель с бизнес-логикой

ISO-недели используются в:

  • финансовой отчётности (недельные закрытия)
  • логистике (маршруты и графики поставок)
  • мониторинге метрик (weekly KPI)
  • планировании спринтов в Agile-системах

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