C#. Сколько недель затрагивается между двумя датами?

Использовал раньше формулу

double weeks = (Model.MaxDate - Model.MinDate).Value.TotalDays / 7;

А потом просто округлял в большую сторону, но чуть позже возник парадокс - если мы выберем промежуток дат между 12.11.2020 до 17.11.2020 - то по формуле это одна неделя(дней то <= 7), а по реальному времени - недели две.

Каким образом это можно учесть и исправить? На вход могу подавать любые даты, их разница только в том что максимальное значение всегда больше минимального, хотя бы на день( т.е. MIN = 12.11.2020 - MAX - не может быть меньше 13.11.2020)


Ответы (2 шт):

Автор решения: AskAlexandria
DateTime StartDate = Model.MinDate.Value;
DateTime diff = StartDate.AddDays(((int)DayOfWeek.Sunday - (int)StartDate.DayOfWeek));
double weeks = Math.Ceiling((Model.MaxDate - diff).Value.TotalDays / 7);

Как то так получилось. Отсчет новой недели лучше брать с воскресенья(в формуле переменной diff), иначе если брать ПН за начало недели, то последний день который выпадает на ПН - игнорится.

→ Ссылка
Автор решения: A K

Вижу, что вы уже нашли себе решение пока я писал, что я имел ввиду, но уж допишу, хотя решение получается более громоздкое.

Вы можете определить для любой даты какой у неё номер недели, например:

var currentDate = new DateTime(2020, 11, 12);
var calendar = CultureInfo.CurrentCulture.Calendar;
var weekNum = calendar.GetWeekOfYear(currentDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

Выведет 46тую неделю для указанной выше даты.

Считайте для вашего интервала в какие недели попадают ваши даты (например: 46тая, 46тая, 47мая) и находите сколько разных недель попало в ваш интервал.

Вот так:

private int PlacedWeeks(DateTime start, DateTime finish)
{
    var calendar = CultureInfo.CurrentCulture.Calendar;

    var weeks = new List<int>();

    var currentDate = start;

    while (currentDate < finish)
    {
        weeks.Add(calendar.GetWeekOfYear(currentDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday));
        currentDate = currentDate.AddDays(1);
    }
    return weeks.Distinct().Count();
}

По идее, логичнее было бы брать HashSet:

private int PlacedWeeks(DateTime start, DateTime finish)
{
    var calendar = CultureInfo.CurrentCulture.Calendar;

    var weeks = new HashSet<int>();

    var currentDate = start;

    while (currentDate < finish)
    {
        weeks.Add(calendar.GetWeekOfYear(currentDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday));
        currentDate = currentDate.AddDays(1);
    }
    return weeks.Count();
}

Ну или сделать в linq:

private int PlacedWeeks(DateTime start, DateTime finish)
{
    var calendar = CultureInfo.CurrentCulture.Calendar;

    var sp = finish - start;
    
    return Enumerable.Range(0, sp.Days)
                     .Select(x => calendar.GetWeekOfYear(start.AddDays(x), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday))
                     .Distinct()
                     .Count();
}

Все варианты дают для ваших дат то, что вы просили:

var d1 = new DateTime(2020, 11, 12);
var d2 = new DateTime(2020, 11, 20);

PlacedWeeks(d1, d2).Dump();

PS Пока писал - понял, что можно было просто взять разницу номеров недель для крайних точек интевала:

private int PlacedWeeks(DateTime start, DateTime finish)
{
    var calendar = CultureInfo.CurrentCulture.Calendar;

    var startWeek = calendar.GetWeekOfYear(start, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    var finishWeek = calendar.GetWeekOfYear(finish, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    
    return finishWeek - startWeek + 1;
}
→ Ссылка