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

Календарный год определяется исключительно границами григорианского календаря: с 1 января по 31 декабря. Любая дата внутри этого диапазона принадлежит одному и тому же году независимо от того, на какую неделю она попадает и как распределяются недели по ISO-правилам. В Day.js это значение возвращается через метод year() и соответствует привычному представлению даты в календарной системе.

\text{year = calendar_year (Jan 1 Dec 31)

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


Недельный год (week-year) строится не вокруг 1 января, а вокруг системы нумерации недель. В ISO-8601 неделя:

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

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

\text{week_year calendar_year (в граничных датах)

В Day.js недельный год доступен через плагины, связанные с ISO-неделями. Чаще всего используются:

  • isoWeek — расширяет работу с неделями по ISO-правилам
  • weekYear — добавляет методы получения недельного года
  • иногда isoWeekYear как более явная ISO-версия

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

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

Рассмотрим дату: 31 декабря.

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

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

  • календарный год: 2025
  • дата: 31 декабря 2025
  • ISO-неделя: может относиться уже к первой неделе 2026 года
  • недельный год: 2026

Обратная ситуация возможна в начале января:

  • дата: 1–3 января
  • календарный год: 2026
  • ISO-неделя: последняя неделя 2025 года
  • недельный год: 2025

Это приводит к ситуации, когда одна и та же дата «живет» в двух разных годовых системах.


Подключение и базовая работа в Day.js

Для работы с недельным годом необходимо расширить Day.js соответствующими плагинами:

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

dayjs.extend(isoWeek)
dayjs.extend(weekYear)

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


Различие методов year() и weekYear()

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

  • year() — календарный год
  • weekYear() — год, определяемый системой недель
dayjs('2025-12-31').year()      // 2025
dayjs('2025-12-31').weekYear()  // может быть 2026

Ключевая проблема, которую решает weekYear(), заключается в корректной группировке данных по неделям. Если отчёт строится по неделям, использование year() приводит к разрыву логики: последняя неделя декабря может оказаться в одном году, а первые дни января — в другом, хотя по недельной структуре это одна сущность.


ISO-неделя и её влияние на год

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

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

Это правило создаёт смещение границ года относительно календаря.

Из-за этого смещения недельный год не синхронизирован с календарным на 100%.


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

Дата: 29 декабря 2024

  • календарный год: 2024
  • ISO-неделя: может уже относиться к 2025
  • недельный год: 2025

Дата: 2 января 2026

  • календарный год: 2026
  • ISO-неделя: может относиться к последней неделе 2025
  • недельный год: 2025

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


Сравнение в логике агрегации данных

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

Если использовать календарный год:

  • неделя 52 декабря 2025 и неделя 1 января 2026 окажутся в разных группах
  • возникает разрыв недельной последовательности

Если использовать недельный год:

  • все недели идут непрерывно
  • границы года становятся вторичными
const d = dayjs('2025-12-31')

const calendar = {
  year: d.year()
}

const weekBased = {
  weekYear: d.weekYear(),
  week: d.isoWeek()
}

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


Связь с ISO-номером недели

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

  • isoWeek() — номер недели
  • weekYear() — год этой недели

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

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

const period = `${d.weekYear()}-W${d.isoWeek()}`

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


Типичные ошибки при смешивании систем

Основные проблемы возникают при смешивании календарного и недельного подходов:

  1. Использование year() с isoWeek() → недели разъезжаются по разным годам

  2. Группировка по дате без учёта недельной логики → нарушается целостность временных интервалов

  3. Хранение week-number без week-year → невозможность однозначно восстановить период

Корректная модель всегда включает пару: недельный год + номер недели.


Внутренняя модель времени в Day.js

Day.js опирается на неизменяемую структуру объекта даты. При подключении плагинов добавляются вычисляемые представления времени, но сама дата остаётся неизменной.

Это означает:

  • year() — прямое чтение календарного компонента
  • weekYear() — вычисляемое значение на основе ISO-алгоритма
  • изменение одного не влияет на другое

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


Поведение в длинных периодах

На больших диапазонах данных (несколько лет) различие становится более заметным:

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

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

52


Итоговая смысловая граница двух систем

Календарный год — это административная и человеческая система отсчёта времени.

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

Day.js предоставляет обе модели одновременно, позволяя переключаться между ними в зависимости от задачи без преобразования даты в сторонние структуры.