Год недели по ISO

ISO-недельная система датирования (ISO 8601) вводит отдельное понятие календарной недели и связанного с ней «года недели» (ISO week-numbering year). В отличие от стандартного календарного года, который начинается 1 января, недельный год привязан к первой неделе, содержащей первый четверг года.

Ключевая особенность:

  • первая неделя года — это неделя, содержащая 4 января;
  • год недели может не совпадать с календарным годом;
  • границы года «размываются» по неделям.

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


Подключение поддержки ISO-недель в Day.js

В библиотеке Day.js работа с ISO-неделями реализуется через плагины. Базовая установка не включает недельные вычисления ISO, поэтому требуется расширение функциональности.

Основные плагины:

  • isoWeek — добавляет ISO-недели
  • isoWeekYear — добавляет поддержку ISO-недельного года

Пример подключения:

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

dayjs.extend(isoWeek)
dayjs.extend(isoWeekYear)

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


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

Календарный год:

dayjs('2025-01-01').year() // 2025

ISO-недельный год:

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

Эти значения могут различаться на границах года.

Пример перехода года

dayjs('2024-12-30').isoWeekYear() // может быть 2025
dayjs('2025-01-01').isoWeekYear() // может быть 2025 или 2024 в зависимости от недели

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


Метод isoWeekYear()

Метод isoWeekYear() возвращает год, к которому относится ISO-неделя даты.

dayjs().isoWeekYear()

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

  • вычисляет год на основе ISO-недели;
  • учитывает переходные дни между декабрём и январём;
  • всегда согласован с isoWeek().

Метод isoWeek()

Метод isoWeek() возвращает номер недели по ISO-стандарту.

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

Диапазон значений:

  • от 1 до 52 (иногда 53 в длинных годах)

Взаимосвязь с isoWeekYear

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

  • isoWeekYear() — год недели
  • isoWeek() — номер недели

Эта пара уникально идентифицирует любую дату в рамках ISO-календаря.


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

ISO-недельный год строится вокруг недельных блоков:

  • неделя всегда начинается в понедельник;
  • первая неделя года — та, в которой есть 4 января;
  • каждая неделя принадлежит ровно одному ISO-году.

Пример распределения

Дата ISO-неделя ISO-год
2024-12-30 1 2025
2024-12-31 1 2025
2025-01-01 1 2025
2025-01-02 1 2025

Это демонстрирует смещение границы года относительно календаря.


Сравнение year() и isoWeekYear()

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

  • year() — календарный год
  • isoWeekYear() — год недельного календаря

Пример различий

const d = dayjs('2024-12-31')

d.year()         // 2024
d.isoWeekYear()  // 2025

Такое расхождение критично для:

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

Совместная работа isoWeek и isoWeekYear

Корректная работа с ISO-календарём требует использования обеих функций одновременно:

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

const week = d.isoWeek()
const year = d.isoWeekYear()

console.log(`${year}-W${week}`)

Результат формирует стандартный ISO-идентификатор недели.


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

Часто используется строковый формат:

YYYY-Www

Пример реализации:

function formatIsoWeek(date) {
  const d = dayjs(date)
  const year = d.isoWeekYear()
  const week = String(d.isoWeek()).padStart(2, '0')
  return `${year}-W${week}`
}

formatIsoWeek('2024-12-31') // 2025-W01

Такой формат применяется в:

  • аналитических системах
  • BI-отчётах
  • планировании спринтов
  • календарях задач

Особенности ISO-недель в Day.js

1. Зависимость от локали

ISO-недели не зависят от локали, в отличие от обычных недель Day.js.

2. Фиксированный старт недели

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

3. Поддержка 53-й недели

В некоторых годах возникает дополнительная неделя:

dayjs('2015-12-31').isoWeek() // 53

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

Ошибка 1: использование year() вместо isoWeekYear()

// некорректно для недельной аналитики
const y = dayjs(date).year()

Ошибка 2: смешивание week() и isoWeek()

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

dayjs.extend(isoWeek)

// правильно
dayjs(date).isoWeek()

// потенциально некорректно
dayjs(date).week()

Ошибка 3: игнорирование плагина isoWeekYear

Без подключения плагина метод отсутствует или возвращает ошибку:

dayjs.extend(isoWeekYear)

Использование в аналитике и отчётности

ISO-недельный год используется при построении:

  • недельных дашбордов
  • отчётов по KPI
  • временных рядов
  • агрегаций данных

Пример агрегации:

const grouped = {}

data.forEach(item => {
  const key = `${dayjs(item.date).isoWeekYear()}-${dayjs(item.date).isoWeek()}`
  grouped[key] = (grouped[key] || 0) + item.value
})

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

Особенно важны переходные дни:

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

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


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

const dates = [
  '2024-12-29',
  '2024-12-30',
  '2024-12-31',
  '2025-01-01',
  '2025-01-02'
]

dates.forEach(d => {
  const dt = dayjs(d)
  console.log(d, dt.isoWeekYear(), dt.isoWeek())
})

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