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 шт):
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), иначе если брать ПН за начало недели, то последний день который выпадает на ПН - игнорится.
Вижу, что вы уже нашли себе решение пока я писал, что я имел ввиду, но уж допишу, хотя решение получается более громоздкое.
Вы можете определить для любой даты какой у неё номер недели, например:
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;
}