Как определить, произошел ли день рождения или юбилей в диапазоне дат
Учитывая, что у меня есть день рождения/годовщина DateTime, как я могу определить, произошла ли эта дата в течение определенного диапазона дат? Например,
День рождения = 1/2/2000
Диапазон дат = 12/25/2008 - 1/3/2009
Мне нужен метод, чтобы определить, произошел ли этот день рождения человека в этот диапазон дат - предпочтительно на С#.
Сначала я решил изменить год рождения DateTime, чтобы он соответствовал диапазону дат, а затем просто проверьте, что "новый" день рождения DateTime находится между датой начала и окончания диапазона дат... но когда диапазон дат охватывает в разные годы, как в моем примере выше, мне пришлось добавить неприятное утверждение if. Нет лучшего способа?
Ответы
Ответ 1
Хорошо, вот мой прием
public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end)
{
DateTime temp = birthday.AddYears(start.Year - birthday.Year);
if (temp < start)
temp = temp.AddYears(1);
return birthday <= end && temp >= start && temp <= end;
}
Ответ 2
Я предполагаю, что ваши даты хранятся в переменных DateTime? Если это так, сравнение довольно прямолинейно:
if (Birthday > DateRangeLower && Birthday < DateRangeUpper) {
// it your birthday!
}
Вы можете инкапсулировать это в метод расширения, если хотите:
public static bool Between(this DateTime compareDate, DateTime startDate, DateTime endDate) {
return compareDate > startDate && compareDate < endDate;
}
то вы можете вызвать его так:
if (Birthday.Between(DateRangeLower, DateRangeUpper) {
// it your birthday
}
Обновить. Если вы хотите проигнорировать часть года рождения, чтобы определить, находится ли юбилей даты в пределах диапазона, примените следующее:
if (DateRangeLower.DayOfYear <= DateRangeUpper.DayOfYear &&
Birthday.DayOfYear > DateRangeLower.DayOfYear && Birthday.DayOfYear < DateRangeUpper.DayOfYear) {
// it your birthday
// the days are within the date range (and the range is in a single year)
}
else if (DateRangeLower.DayOfYear > DateRangeUpper.DayOfYear &&
Birthday.DayOfYear < DateRangeLower.DayOfYear && Birthday.DayOfYear > DateRangeUpper.DayOfYear) {
// it your birthday
// note, we're actually checking to see if the date is outside of the
// original date days to handle the case where the dates span a year end boundary
// this only works if the dates are not more than 1 year apart
}
Ответ 3
Обновлен ответ, чтобы включить нормализацию верхней границы, упомянутую SLC. Это должно работать в тех случаях, когда человек не родился и не родился 29/02.
DateTime birthday = new DateTime(2000, 2, 1);
DateTime min = new DateTime(2008, 12, 25);
DateTime max = new DateTime(2009, 3, 1);
DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day);
DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day);
if (birthday.Year <= max.Year &&
((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max)))
{
// Happy birthday
Console.WriteLine("Happy birthday");
}
И теперь версия, которая обрабатывает людей, родившихся в день (29/02):
public static bool IsBirthdayInRange(
DateTime birthday, DateTime min, DateTime max)
{
var dates = new DateTime[] { birthday, min };
for (int i = 0; i < dates.Length; i++)
{
if (dates[i].Month == 2 && dates[i].Day == 29)
{
dates[i] = dates[i].AddDays(-1);
}
}
birthday = dates[0];
min = dates[1];
DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day);
DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day);
if (birthday.Year <= max.Year &&
((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max)))
{
return true;
}
return false;
}
Ответ 4
Вы можете использовать свойство DayOfYear объектов DateTime.
if ((birthday.DayOfYear >= start.DayOfYear) && (birthday.DayOfYear <= end.DayOfYear)) {
...
}
Ответ 5
Вот мое решение. Для поиска соответствия используется DayOfYear
. Но вам нужно позаботиться, если DayOfYear
даты начала прошло DayOfYear
конечной даты. Я предполагаю, что дата начала раньше даты окончания:
private static bool HasBirthDay( DateTime birthday, DateTime start, DateTime end )
{
Debug.Assert( start < end );
if( start.DayOfYear < end.DayOfYear )
{
if( birthday.DayOfYear > start.DayOfYear && birthday.DayOfYear < end.DayOfYear )
{
return true;
}
}
else
{
if( birthday.DayOfYear < end.DayOfYear || birthday.DayOfYear > start.DayOfYear )
{
return true;
}
}
return false;
}
// DayOfYear(start date) > DayOfYear(end date)
var start = new DateTime( 2008, 12, 25 );
var end = new DateTime( 2009, 1, 3 );
Debug.Assert( HasBirthDay( new DateTime( 2000, 1, 2 ), start, end ) );
Debug.Assert( HasBirthDay( new DateTime( 2000, 12, 26), start, end ) );
Debug.Assert( !HasBirthDay( new DateTime( 2000, 1, 5 ), start, end ) );
Debug.Assert( !HasBirthDay( new DateTime( 2000, 12, 24 ), start, end ) );
// DayOfYear(start date) < DayOfYear(end date)
start = new DateTime( 2008, 10, 25 );
end = new DateTime( 2008, 11, 3 );
Debug.Assert( HasBirthDay( new DateTime( 2000, 10, 26 ), start, end ) );
Debug.Assert( !HasBirthDay( new DateTime( 2000, 12, 5 ), start, end ) );
Debug.Assert( !HasBirthDay( new DateTime( 2000, 1, 24 ), start, end ) );
Ответ 6
Суть вашей проблемы заключается в том, чтобы определить, какой Год назначить на День рождения, чтобы убедиться, что вы можете выполнить допустимое сравнение диапазона.
У вас есть два подслучая, относящихся к диапазону, с которым вам нужно иметь дело:
- У LowerBound есть тот же год, что и UpperBound
- У LowerBound есть другой год от UpperBound
EDIT: недостаточно кофе. Игнорируйте мой предыдущий ответ.
Вам нужно настроить даты в зависимости от месяца/дня вашего дня рождения.
Вы не всегда можете использовать верхний граничный год, потому что день рождения может упасть на месяц, который больше, чем месяц верхней границы. Одна простая альтернатива заключается в том, чтобы дважды выполнить проверку: один раз с использованием верхнего граничного года, а затем снова с использованием предшествующего года. Это обрабатывает случаи границ года:
var birthday = DateTime.Parse( "1/2/2000" );
var lowerBound = DateTime.Parse( "12/25/2008" );
var upperBound = DateTime.Parse( "1/3/2009" );
var adjustA = new Birthday( upperBound.Year, birthday.Month, birthday.Day );
var adjustB = adjustA.AddYears( -1 );
var isInBounds = (adjustA >= lowerBound && adjustA <= upperBound) ||
(adjustB >= lowerBound && adjustB <= upperBound);
Ответ 7
Я бы просто конвертировал все даты в эпоху Epoch, а затем сделал прямое сравнение.
Я нашел это преобразование здесь, слегка измененный
int epoch = (int)({Beginning/Ending Date} - new DateTime(1970, 1, 1)).TotalSeconds;
Таким образом, весь ваш код будет
int StartDateInEpoch = (int)(StartDate - new DateTime(1970, 1, 1)).TotalSeconds;
int EndDateInEpoch = (int)(EndDate - new DateTime(1970, 1, 1)).TotalSeconds;
int TargetDateInEpoch = (int)(TargetDate - new DateTime(1970, 1, 1)).TotalSeconds;
if (StartDateInEpoch < TargetDateInEpoch && TargetDateInEpoch <= EndDateInEpoch)
return true;
Ответ 8
Другой ответ, переводя все даты в определенный год.
public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end)
{
// This could be any date...
var epoch = new DateTime(1970, 1, 1);
// Start date is always epoch, end date is epoch + range span
DateTime endDateInEpoch = epoch.AddSeconds((end - start).TotalSeconds);
// Move the bithday back to epoch.Year
DateTime birthDayInEpoch = birthday.AddYears(epoch.Year - birthday.Year);
return birthday <= end && epoch < birthDayInEpoch && birthDayInEpoch <= endDateInEpoch;
}
Ответ 9
if (Birthday.Month >= DateRangeLower.Month && Birthday.Month <= DateRangeUpper.Month
&& Birthday.Day>= DateRangeLower.Day && Birthday.Day<= DateRangeUpper.Day) {
//Partytime...
}
Ответ 10
Возможно, вам лучше всего сделать снимок для этого.
Проблема заключается в фундаментальном определении того, существует ли такое N, что человек N-й день рождения находится в диапазоне или нет.
Вы можете взять базовый уровень и выполнить расчет числа дней с помощью модуля, который будет обрабатывать опрокидывание года (но високосные годы могут приводить к ошибкам "один за другим" ).
Еще одна альтернатива, которая может привести к более простому представлению, заключается в том, что, поскольку дни рождения образуют одномерную сетку на линии календаря, поскольку день рождения НЕ входит в диапазон, диапазон должен полностью находиться между днями рождения человека в последующие годы: ie NOT (BirthdayY1 < RangeStart & & RangeEnd < BirthdayY2).
Обычно, когда мы проводили такой анализ, это было целыми месяцами, поэтому было гораздо проще найти все дни рождения в мае, например, чтобы получить поздравительные открытки.
Ответ 11
Установите день рождения в год = 2000, с даты на год = 2000 и на дату до 2000 года. Если дата до даты с даты, установите дату на 2001 год.
После этого махинации, сверху:
if (Birthday > DateRangeLower && Birthday < DateRangeUpper) {
// it your birthday!
}
Ответ 12
Будет ли это работать!!!
for(int i = startDate.year; i <= endDate.year; i++)
{
DateTime newBD = new DateTime(i, BD.month, BD.day);
if((DateTime.Compare(newBD, startDate) >= 0) && (DateTime.Compare(newBD, endDate) <= 0))
{
//gotcha
break;
}
}
Ответ 13
Этот должен правильно обрабатывать високосные годы:
public static bool IsBirthdayInRange(DateTime birthday, DateTime from, DateTime to)
{
if (to < from)
{
throw new ArgumentException("The specified range is not valid");
}
int year = from.Year;
int month = birthday.Month;
int day = birthday.Day;
if (from.DayOfYear > to.DayOfYear && birthday.DayOfYear < from.DayOfYear)
{
year++;
}
if (month == 2 && day == 29 && !DateTime.IsLeapYear(year))
{
// Assuming people born on February 29 celebrate their birthday
// one day earlier on non-leap years
day--;
}
DateTime bDate = new DateTime(year, month, day);
return bDate >= from.Date && bDate <= to.Date;
}