У меня есть небольшой способ получить количество участников в определенном возрастном диапазоне. Предполагается, что диапазон включает оба конца, т. е. если я назову CountSelection(memberList, 16, 19)
(где memberList
— это List<Member>
), я ожидаю получить общее количество участников в возрасте 16, 17, 18 и 19 лет:
private int CountSelection(List<Member> members, int minAge, int maxAge)
{
DateTime from = DateTime.Now.AddYears(minAge * -1);
DateTime to = DateTime.Now.AddYears(maxAge * -1);
return members.Count(m =>
m.DateBorn.Date <= from.Date &&
m.DateBorn.Date >= to.Date);
}
Однако мой метод ненадежен - иногда он пропускает членов, я предполагаю, что когда даты рождения попадают между диапазонами. В основном методе я вызываю CountSelection()
несколько раз, каждый с разными диапазонами, теоретически охватывающими все возрасты.
Как должен выглядеть запрос, чтобы гарантировать, что будут учтены все члены?
Вам не нужно умножать на -1, вы можете просто инвертировать выражение напрямую. Например, DateTime.Now.AddYears(-minAge)
:)
Возраст не совпадает с годом рождения человека...
Вопрос в том, если кто-то родился в феврале 2017 года, им два или три года? Если maxAge = 2, они не включаются. Когда у вас есть диапазон, минимум должен быть >=, а максимум должен быть только <, иначе у вас будет один дополнительный день.
Использовать DateTime.Date.AddYears? DateTime.Now.AddYears включает компонент времени.
Я понял, почему мой метод не работает. Я просто вычитал целые годы из дат от и до, и в результате диапазоны выглядели следующим образом (формат даты дд.мм.гггг):
0-5 years - 11.04.2014-11.04.2019
6-12 years - 11.04.2007-11.04.2013
13-19 years - 11.04.2000-11.04.2006
20-26 years - 11.04.1993-11.04.1999
... and so on.
Обратите внимание на разрыв почти в год между каждым диапазоном.
Решение:
Вместо того, чтобы устанавливать дату начала следующим образом:
DateTime from = DateTime.Now.Date.AddYears(-maxAge);
Я, конечно, должен вычесть еще 1 год и добавить 1 день:
DateTime from = DateTime.Now.Date.AddYears(-maxAge + 1).AddDays(1);
Теперь диапазоны выглядят так:
0-5 years - 12.04.2013-11.04.2019
6-12 years - 12.04.2006-11.04.2013
13-19 years - 12.04.1999-11.04.2006
20-26 years - 12.04.1992-11.04.1999
... and so on.
Окончательный рабочий метод выглядит так:
private int CountSelection(List<Member> members, int minAge, int maxAge)
{
DateTime from = compareDate.AddYears(-maxAge+1).AddDays(1);
DateTime to = compareDate.AddYears(-minAge);
return members.Count(m =>
m.DateBorn >= from &&
m.DateBorn <= to);
}
С диапазонами с исключающими верхними границами работать проще:
private int CountSelection(List<Member> members, int minAge, int maxAgeExclusive)
{
DateTime from = compareDate.AddYears(-maxAgeExclusive);
DateTime to = compareDate.AddYears(-minAge);
return members.Count(m => m.DateBorn > from && m.DateBorn <= to);
}
Теперь ваши диапазоны будут математически более последовательными.
0-6 years
6-13 years
13-20 years
20-27 years
etc
Затем вы можете вычесть единицу из верхнего предела на уровне представления.
Я думаю, что ваши даты
from
иto
поменялись местами. Судя по тому, как написан ваш код, датаto
соответствует дате доfrom
, что кажется неправильным.