Год недели

В классическом календаре год начинается 1 января, однако во многих системах учёта используется понятие недельного года — года, основанного на неделях. В Moment.js для работы с такими значениями предусмотрен отдельный набор методов.

Недельный год особенно важен в:

  • бухгалтерских системах;
  • ISO-календарях;
  • системах аналитики;
  • ERP и CRM;
  • отчётах по неделям;
  • логистике и производственных циклах.

Отличие обычного года от года недели

Обычный год:

moment('2025-01-01').year()

возвращает:

2025

Однако недельный год может отличаться:

moment('2025-01-01').weekYear()

или:

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

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


ISO-недельный календарь

Стандарт ISO-8601 определяет:

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

Например:

Дата Календарный год ISO-недельный год
2020-12-31 2020 2020
2021-01-01 2021 2020
2021-01-04 2021 2021

Метод weekYear()

Метод weekYear() работает с локализованным недельным годом.

Получение года недели

const date = moment('2025-01-01');

console.log(date.weekYear());

Метод isoWeekYear()

Метод isoWeekYear() использует ISO-стандарт.

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

const date = moment('2021-01-01');

console.log(date.isoWeekYear());

Результат:

2020

Потому что дата относится к последней ISO-неделе 2020 года.


Разница между year() и isoWeekYear()

const date = moment('2021-01-01');

console.log(date.year());
console.log(date.isoWeekYear());

Результат:

2021
2020

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

Часто год недели используется вместе с номером недели.

const date = moment('2021-01-01');

console.log(date.isoWeek());
console.log(date.isoWeekYear());

Результат:

53
2020

Форматирование года недели

Moment.js поддерживает специальные токены форматирования.

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

moment('2021-01-01').format('GGGG')

Результат:

2020

Основные токены

Токен Описание
gggg локальный год недели
gg локальный год недели (2 цифры)
GGGG ISO-год недели
GG ISO-год недели (2 цифры)

Пример форматирования

const date = moment('2021-01-01');

console.log(date.format('YYYY'));
console.log(date.format('GGGG'));

Результат:

2021
2020

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

Изменение локального года недели

const date = moment();

date.weekYear(2030);

console.log(date.format());

Изменение ISO-года недели

const date = moment();

date.isoWeekYear(2030);

console.log(date.format());

Moment.js автоматически корректирует дату в соответствии с неделей.


Как работает пересчёт

При изменении недельного года Moment.js:

  1. сохраняет номер недели;
  2. сохраняет день недели;
  3. переносит дату в новый недельный год.

Пример:

const date = moment('2021-01-05');

console.log(date.format());

date.isoWeekYear(2025);

console.log(date.format());

Использование вместе с isoWeek()

const date = moment();

date.isoWeekYear(2025);
date.isoWeek(10);
date.isoWeekday(3);

console.log(date.format());

Здесь:

  • isoWeekYear(2025) — ISO-год;
  • isoWeek(10) — 10 неделя;
  • isoWeekday(3) — среда.

Создание даты из ISO-недельного года

const date = moment()
    .isoWeekYear(2025)
    .isoWeek(1)
    .isoWeekday(1);

console.log(date.format());

Получение первого понедельника ISO-года.


Парсинг ISO-недельной даты

Moment.js умеет разбирать недельные даты.

const date = moment('2025-W10-3', 'GGGG-[W]WW-E');

console.log(date.format());

Разбор формата

Часть Значение
GGGG ISO-года недели
WW номер недели
E ISO-день недели

Работа с локализованным недельным годом

Методы:

week()
weekYear()
weekday()

зависят от локали.

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

  • США — воскресенье;
  • Европа — понедельник.

ISO-методы

ISO-методы всегда работают одинаково:

isoWeek()
isoWeekYear()
isoWeekday()

Это делает их предпочтительными для международных систем.


Определение количества недель в году

Локализованный вариант

moment().weeksInYear()

ISO-вариант

moment().isoWeeksInYear()

Пример ISO-недель в году

console.log(moment('2020').isoWeeksInYear());
console.log(moment('2021').isoWeeksInYear());

Результат:

53
52

Почему некоторые годы содержат 53 недели

53 недели появляются, если:

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

Проверка принадлежности даты к ISO-году

const date = moment('2021-01-01');

if (date.isoWeekYear() === 2020) {
    console.log('Дата относится к ISO-году 2020');
}

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

Для отчётов часто используется комбинированный ключ:

const key = moment().format('GGGG-[W]WW');

Пример результата:

2025-W08

Такой формат удобен для:

  • аналитики;
  • BI-систем;
  • SQL-агрегаций;
  • финансовых отчётов.

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

const start = moment()
    .isoWeekYear(2025)
    .startOf('isoWeek');

console.log(start.format());

Получение конца ISO-года

const end = moment()
    .isoWeekYear(2025)
    .isoWeek(moment().isoWeeksInYear())
    .endOf('isoWeek');

console.log(end.format());

Сравнение дат по недельному году

const a = moment('2021-01-01');
const b = moment('2020-12-31');

console.log(
    a.isoWeekYear() === b.isoWeekYear()
);

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

Частый сценарий:

const reportDate = moment();

const reportKey = {
    year: reportDate.isoWeekYear(),
    week: reportDate.isoWeek()
};

console.log(reportKey);

Группировка данных

const group = moment(date)
    .format('GGGG-[W]WW');

Пример:

2025-W14

Работа с временными зонами

При использовании moment-timezone недельный год зависит от временной зоны.

const date = moment.tz(
    '2021-01-01 01:00',
    'Europe/Berlin'
);

console.log(date.isoWeekYear());

Возможные ошибки

Путаница между YYYY и GGGG

Неправильно:

moment().format('YYYY-WW')

Правильно:

moment().format('GGGG-[W]WW')

Смешивание week() и isoWeek()

Нежелательно смешивать:

week()
isoWeek()

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


Практический пример календаря отчётов

function getWeeklyReportId(date) {
    return moment(date)
        .format('GGGG-[W]WW');
}

console.log(
    getWeeklyReportId('2021-01-01')
);

Результат:

2020-W53

Генерация диапазона ISO-недель

const start = moment()
    .startOf('isoWeek');

for (let i = 0; i < 7; i++) {
    console.log(
        start.clone().add(i, 'days').format()
    );
}

Проверка перехода между ISO-годами

const dates = [
    '2020-12-31',
    '2021-01-01',
    '2021-01-04'
];

dates.forEach(date => {
    const m = moment(date);

    console.log({
        date,
        year: m.year(),
        isoYear: m.isoWeekYear(),
        isoWeek: m.isoWeek()
    });
});

Использование в SQL и API

Формат недельного года часто используется в REST API:

{
    year: 2025,
    week: 12
}

или:

2025-W12

Moment.js позволяет легко формировать такие идентификаторы.


Производительность

Операции с недельными годами выполняются быстро, однако при массовой обработке данных рекомендуется:

  • избегать лишнего создания объектов moment;
  • использовать clone() вместо повторного парсинга;
  • минимизировать форматирование внутри циклов.

Совместимость

Методы недельного года поддерживаются:

  • в браузерах;
  • в Node.js;
  • в Moment Timezone;
  • во всех актуальных версиях Moment.js.

Связанные методы

Метод Назначение
week() локальная неделя
weeks() алиас week
isoWeek() ISO-неделя
weekYear() локальный недельный год
isoWeekYear() ISO-недельный год
weekday() локальный день недели
isoWeekday() ISO-день недели
weeksInYear() недель в локальном году
isoWeeksInYear() ISO-недель в году