Почему в календаре бывает 53 недели

Согласно ГОСТ ИСО 8601-2001 “ПРЕДСТАВЛЕНИЕ ДАТ И ВРЕМЕНИ” расчет номера недели в Российской Федерации осуществляется так:

Первой неделей года является та неделя, которая содержит число 4 января. То есть если первое января выпадает на пятницу, субботу, или воскресенье, то все еще продолжается последняя неделя предыдущего года.

Это может приводить к интересным спецэффектам - в году может содержаться 52 или 53 недели, 29, 30, 31 декабря могут относиться к первой неделе следующего года, и наоборот, 1, 2, и 3 января могут относиться к 52 или 53 неделе прошлого года. В частности 53 недели содержали 2015 и 2020 годы.

Привычный подход к вычислению количества недель в году с помощью Calendar.GetWeekOfYear для нашего ГОСТа даёт сбой и работает некорректно. 53-и недели при таком подходе отсустсвуют.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Такой подход вычисляет 53-ю неделю НЕКОРРЕКТНО
var ruCi = new CultureInfo("ru-RU");
var ruCal = ruCi.Calendar;
var ruCwr = ruCi.DateTimeFormat.CalendarWeekRule;
var ruFirstDow = ruCi.DateTimeFormat.FirstDayOfWeek;

for (var i = 1; i < dateTimeRanges.Count; i++)
{
var year = dateTimeRanges[i].Add(reportDto.ClientOffset).Year.ToString("D4");
var nn = ruCal.GetWeekOfYear(
dateTimeRanges[i].Add(reportDto.ClientOffset),
ruCwr,
ruFirstDow
).ToString("D2"); // вычисляет 53-ю неделю НЕКОРРЕКТНО !!!
worksheet.Cells[4, shift + i].Value = $"{nn}.{year}"; // НЕКОРРЕКТНОЕ значение для 53-ей недели!!!
}

Метод Calendar.GetWeekOfYear вычиляет недели в году не по ГОСТ ИСО 8601-2001 и для календаря РФ не подходит!

Для расчёта недель согласно ГОСТ ИСО 8601-2001 следует использовать статический класс ISOWeek и метод GetWeekOfYear:

1
2
3
4
5
6
7
8
for (var i = 1; i < dateTimeRanges.Count; i++)
{
var year = ISOWeek.GetYear(dateTimeRanges[i].Add(reportDto.ClientOffset)).ToString("D4");
var nn = ISOWeek.GetWeekOfYear(
dateTimeRanges[i].Add(reportDto.ClientOffset)
).ToString("D2"); // ПРАВИЛЬНОЕ значение для 53-ей недели
worksheet.Cells[4, shift + i].Value = $"{nn}.{year}";
}

Подробнее с ISOWeek.GetWeekOfYear можно познакомиться по ссылке