Недели ISO

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

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


Подключение функциональности ISO-недель в Day.js

Базовая библиотека Day.js не включает ISO-недели из коробки. Поддержка добавляется через плагин:

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

dayjs.extend(isoWeek)

После подключения становятся доступны методы и логика, соответствующие ISO 8601.

Ключевой момент: без подключения плагина любые обращения к ISO-неделям будут некорректны или недоступны.


Разница между week и isoWeek

Day.js предоставляет два различных подхода:

  • week() — локальная неделя (зависит от настроек региона)
  • isoWeek() — строго по ISO 8601

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

Параметр week() isoWeek()
Первый день недели зависит от локали всегда понедельник
Первая неделя года локальное правило неделя с первым четвергом
Стабильность между системами низкая высокая

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


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

После подключения плагина появляется метод:

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

Результат — номер недели в году по ISO-стандарту.

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

const date = dayjs('2026-01-03')
console.log(date.isoWeek()) // например, 53 или 1 в зависимости от ISO-границы года

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


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

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

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

Особенность поведения

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

Пример:

const d = dayjs('2026-01-01')

console.log(d.year())        // 2026
console.log(d.isoWeekYear()) // может быть 2025

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


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

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

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

Поведение методов

  • startOf('isoWeek') → понедельник 00:00:00
  • endOf('isoWeek') → воскресенье 23:59:59.999

Пример:

const date = dayjs('2026-05-23')

console.log(date.startOf('isoWeek').format())
console.log(date.endOf('isoWeek').format())

Эти методы особенно полезны при построении диапазонов запросов в базах данных.


Присвоение ISO-недели

Day.js позволяет не только читать, но и изменять неделю:

dayjs().isoWeek(10)

Это устанавливает дату в соответствующую ISO-неделю текущего ISO-года.

Однако важно понимать: установка недели не является «пересчётом внутри месяца», а приводит к смещению даты в календарной шкале.


Работа с границами года

ISO-недели часто пересекают границы календарного года, создавая ситуации, когда:

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

Пример пограничного поведения

dayjs('2019-12-31').isoWeek()
dayjs('2020-01-01').isoWeek()

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

Это фундаментальное отличие от обычной календарной логики.


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

Отчётные системы

ISO-недели применяются для:

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

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

const week = dayjs(eventDate).isoWeek()
const year = dayjs(eventDate).isoWeekYear()

const key = `${year}-W${week}`

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

При построении календарей задач ISO-недели позволяют избежать смещения при смене локали:

const start = dayjs().isoWeek(15).startOf('isoWeek')
const end = dayjs().isoWeek(15).endOf('isoWeek')

Серверная синхронизация

ISO-формат обеспечивает единообразие между:

  • frontend (браузеры разных стран)
  • backend (серверные таймзоны)
  • аналитическими системами

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

ISO-неделя зависит от локального времени объекта Day.js. При работе с UTC необходимо явно фиксировать режим:

import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)

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

Без этого возможны расхождения между локальными и UTC-расчётами.


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

Day.js не предоставляет встроенного форматирования ISO-недель через format, но можно комбинировать данные:

const d = dayjs('2026-05-23')

const label = `${d.isoWeekYear()}-W${String(d.isoWeek()).padStart(2, '0')}`

Результат:

2026-W21

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

Ошибка 1: смешивание week и isoWeek

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

Ошибка 2: игнорирование isoWeekYear

Привязка только к году без ISO-года создаёт ошибки на границе декабря–января.

Ошибка 3: предположение о линейности недель

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


Сравнение с альтернативными календарными подходами

Месячная модель

  • проще визуально
  • хуже подходит для аналитики

Календарные недели (локальные)

  • зависят от региона
  • нестабильны между системами

ISO-недели

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

Внутренние принципы вычисления ISO-недель

Day.js опирается на алгоритм, который:

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

Эта логика обеспечивает соответствие ISO 8601 и стабильность вычислений независимо от локали.