Вычисление номера недели

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

В JavaScript при работе с датами базовый объект Date не предоставляет встроенного универсального метода для вычисления номера недели. Библиотека Day.js решает эту задачу через систему подключаемых плагинов, позволяя гибко выбирать правила расчёта.

Архитектура работы с неделями в Day.js

В Day.js вычисление номера недели реализуется не в ядре библиотеки, а через расширения:

  • weekOfYear — классическое определение недели года с учётом локали
  • isoWeek — стандарт ISO 8601
  • локализационные настройки, влияющие на начало недели

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

Установка и подключение плагинов

Перед использованием функционала недель необходимо подключить соответствующие расширения.

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

dayjs.extend(weekOfYear)
dayjs.extend(isoWeek)

После подключения Day.js получает дополнительные методы:

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

ISO-недели и стандарт ISO 8601

ISO 8601 определяет строгие правила вычисления недель:

  • неделя начинается в понедельник
  • первая неделя года — та, которая содержит 4 января
  • недели нумеруются от 1 до 52 или 53

В Day.js этот стандарт реализуется через метод isoWeek().

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

Метод возвращает номер ISO-недели независимо от локальных настроек.

Связанные методы ISO-недель

Дополнительно доступны:

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

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

Плагин weekOfYear и локальные правила

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

import 'dayjs/locale/ru'
dayjs.locale('ru')

В зависимости от локали меняется:

  • первый день недели (понедельник или воскресенье)
  • правила определения первой недели года

Метод:

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

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

Различие week и isoWeek

Ключевое различие заключается в источнике правил:

Метод Стандарт Зависимость от локали
week() локальный да
isoWeek() ISO 8601 нет

Это различие критично при обработке данных из разных регионов, где календарные стандарты отличаются.

Получение и установка номера недели

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

Получение

dayjs('2026-05-22').isoWeek()
dayjs('2026-05-22').week()

Установка

dayjs().isoWeek(10)
dayjs().week(3)

При установке дата смещается таким образом, чтобы соответствовать указанной неделе текущего года.

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

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

ISO-неделя

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

Локальная неделя

dayjs().startOf('week')
dayjs().endOf('week')

Результат зависит от локали и может отличаться между системами.

Практика расчёта недель в разных сценариях

Календарные сетки

При построении календаря месяца используется вычисление смещения относительно первой недели:

const firstDay = dayjs('2026-01-01')
const weekIndex = firstDay.isoWeek()

Группировка данных по неделям

const grouped = {}

data.forEach(item => {
  const week = dayjs(item.date).isoWeek()

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

  grouped[week].push(item)
})

Аналитика временных рядов

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

const stats = new Map()

for (const row of rows) {
  const key = dayjs(row.timestamp).isoWeek()
  stats.set(key, (stats.get(key) || 0) + row.value)
}

Работа с переходными годами

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

dayjs('2025-12-31').isoWeek()
dayjs('2026-01-01').isoWeek()

Такие случаи важны при построении годовых отчётов, где простая проверка year() недостаточна.

Смещение начала недели и влияние локали

Локаль влияет на интерпретацию:

  • неделя начинается с воскресенья (например, США)
  • неделя начинается с понедельника (большинство европейских локалей)

Это напрямую отражается на результатах week():

dayjs.locale('en')
dayjs().week()

dayjs.locale('ru')
dayjs().week()

Разница может приводить к изменению номера недели для одной и той же даты.

Использование относительных вычислений

Day.js позволяет комбинировать недели с другими методами:

dayjs().startOf('isoWeek').add(2, 'day')
dayjs().subtract(1, 'week').isoWeek()

Такие конструкции применяются для построения диапазонов и навигации по календарю.

Особенности сериализации и хранения

При сохранении номера недели в базе данных важно учитывать:

  • хранить ISO-неделю отдельно от локальной
  • фиксировать год вместе с неделей
  • учитывать пограничные даты

Пример структуры:

{
  "year": 2026,
  "isoWeek": 21
}

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

Сопоставление недель с датами

Обратное преобразование недели в дату:

dayjs().year(2026).isoWeek(10).startOf('isoWeek')

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

Работа с диапазонами недель

Формирование диапазона:

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

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

Влияние перехода на летнее время

Хотя номер недели не зависит напрямую от часового пояса, границы недели могут смещаться при переходе DST, особенно при использовании startOf('week') в локальных системах.

Сравнение поведения в разных версиях локалей

Некоторые локали могут иметь различия:

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

Day.js учитывает эти параметры через систему локалей, что делает поведение предсказуемым при правильной настройке.

Комбинирование с форматированием дат

Номер недели часто используется вместе с форматированием:

dayjs().format('YYYY [week] W')
dayjs().format('GGGG-[W]WW')

Второй вариант соответствует ISO-формату года и недели.