Настройка рабочей недели

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

Начало недели и его влияние на расчёты

Базовая настройка определяется параметром weekStartsOn, который задаёт, какой день считается первым в неделе. Значение варьируется от 0 (воскресенье) до 6 (суббота).

import { startOfWeek, endOfWeek } from 'date-fns'

const date = new Date(2026, 0, 15)

// Неделя, начинающаяся с воскресенья (по умолчанию в en-US локали)
startOfWeek(date, { weekStartsOn: 0 })

// Неделя, начинающаяся с понедельника
startOfWeek(date, { weekStartsOn: 1 })

// Конец недели при разных настройках
endOfWeek(date, { weekStartsOn: 1 })

Изменение weekStartsOn не только смещает границы недели, но и влияет на все функции, которые опираются на недельные интервалы. Это делает параметр критическим при работе с локализованными календарями.

Локали и встроенные правила недели

date-fns поддерживает локали, каждая из которых содержит собственные правила недельной системы. Локаль определяет:

  • первый день недели
  • правило первой недели года
  • форматирование дат
import { startOfWeek } from 'date-fns'
import { ru } from 'date-fns/locale'

const date = new Date(2026, 0, 15)

startOfWeek(date, { locale: ru })

Локаль ru задаёт понедельник как первый день недели, что соответствует распространённой календарной системе в России и большинстве европейских стран.

При использовании локали можно не указывать weekStartsOn вручную, так как локаль уже содержит это значение.

ISO-неделя и её особенности

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

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

В date-fns ISO-логика используется в функциях getISOWeek, startOfISOWeek, endOfISOWeek.

import { getISOWeek, startOfISOWeek } from 'date-fns'

const date = new Date(2026, 0, 1)

getISOWeek(date)
startOfISOWeek(date)

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

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

Функция getWeek вычисляет номер недели в году с учётом параметров локали или пользовательской конфигурации.

import { getWeek } from 'date-fns'

const date = new Date(2026, 0, 15)

getWeek(date, { weekStartsOn: 1 })

Дополнительно учитывается параметр firstWeekContainsDate, который определяет, какой день должен входить в первую неделю года.

getWeek(date, {
  weekStartsOn: 1,
  firstWeekContainsDate: 4
})

Значение firstWeekContainsDate: 4 соответствует ISO-стандарту.

Границы недели

Функции startOfWeek и endOfWeek формируют диапазон недели, что используется в календарях, отчётах и аналитике.

import { startOfWeek, endOfWeek } from 'date-fns'

const date = new Date(2026, 0, 15)

const start = startOfWeek(date, { weekStartsOn: 1 })
const end = endOfWeek(date, { weekStartsOn: 1 })

Результирующий диапазон всегда охватывает 7 дней, но границы зависят от конфигурации.

Глобальная настройка через setDefaultOptions

date-fns позволяет задать единые настройки для всего приложения через setDefaultOptions. Это особенно важно при работе с единым стандартом недели во всём проекте.

import { setDefaultOptions, startOfWeek } from 'date-fns'
import { ru } from 'date-fns/locale'

setDefaultOptions({
  locale: ru,
  weekStartsOn: 1
})

const date = new Date(2026, 0, 15)

startOfWeek(date)

После установки значений по умолчанию все функции, поддерживающие опции, начинают использовать их автоматически, если не переопределены локально.

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

При одновременном использовании locale и weekStartsOn приоритет обычно имеет явное значение weekStartsOn. Это позволяет гибко переопределять поведение локали.

startOfWeek(date, {
  locale: ru,
  weekStartsOn: 0
})

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

firstWeekContainsDate и годовая логика

Параметр firstWeekContainsDate определяет, как вычисляется первая неделя года. Он задаёт, какой день января должен входить в первую неделю, чтобы она считалась неделей года.

  • значение 1 — первая неделя содержит 1 января
  • значение 4 — используется ISO-логика
import { getWeek } from 'date-fns'

const date = new Date(2026, 0, 1)

getWeek(date, {
  weekStartsOn: 1,
  firstWeekContainsDate: 1
})

Изменение этого параметра может существенно влиять на нумерацию недель, особенно в начале января.

Согласованность недельной системы в приложении

При построении календарных интерфейсов важно, чтобы все функции использовали одинаковую конфигурацию. Несогласованность между getWeek, startOfWeek и форматированием дат приводит к логическим разрывам в отображении данных.

Типичная конфигурация для единого стандарта:

const weekOptions = {
  weekStartsOn: 1,
  firstWeekContainsDate: 4
}

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

Форматирование дат с учётом недели

Функция format также учитывает локаль при работе с недельными обозначениями (i, I, w, W).

import { format } from 'date-fns'
import { ru } from 'date-fns/locale'

const date = new Date(2026, 0, 15)

format(date, 'wo yyyy', { locale: ru })

Здесь w обозначает локальную неделю, а I — ISO-неделю, что позволяет разделять разные системы нумерации в одном приложении.

Различия локальной и ISO-недели в практических расчётах

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

  • начало января
  • конец декабря
  • пересечение года в середине недели
import { getWeek, getISOWeek } from 'date-fns'

const date = new Date(2026, 0, 1)

getWeek(date, { weekStartsOn: 0 })
getISOWeek(date)

Разница между результатами может составлять одну единицу, что критично для систем учёта времени и отчётности.

Практика унификации недельной модели

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

// weekConfig.js
export const weekConfig = {
  weekStartsOn: 1,
  firstWeekContainsDate: 4
}

Далее эта конфигурация передаётся во все функции работы с датами.

import { getWeek, startOfWeek } from 'date-fns'
import { weekConfig } from './weekConfig'

getWeek(new Date(), weekConfig)
startOfWeek(new Date(), weekConfig)