Как определить, произошел ли день рождения или годовщина в течение диапазона дат - PullRequest
25 голосов
/ 31 марта 2010

Учитывая, что у меня день / день рождения DateTime, как я могу определить, произошла ли эта дата в течение определенного диапазона дат? Например,

День Рождения = 1/2/2000
Диапазон дат = 25.12.2008 - 1/3/2009

Мне нужен метод, чтобы определить, произошел ли день рождения этого человека во время этого диапазона дат - предпочтительно в C #.

Сначала я изменил год даты и времени дня рождения в соответствии с диапазоном дат, а затем просто проверил, находится ли «новый» день и дата конца дня между начальной и конечной датой диапазона дат ... но когда диапазон дат охватывает разные годы, как в моем примере выше - мне пришлось добавить противное утверждение if. Нет лучшего способа?

Ответы [ 13 ]

10 голосов
/ 31 марта 2010

Хорошо, вот мой дубль

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 голосов
/ 31 марта 2010

Обновлен ответ , чтобы включить нормализацию верхней границы, упомянутую 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;
}
2 голосов
/ 31 марта 2010

Я предполагаю, что ваши даты хранятся в переменных DateTime? Если это так, сравнение довольно простое:

if (Birthday > DateRangeLower && Birthday < DateRangeUpper) {
    // it's your birthday!
}

Вы можете заключить это в метод расширения, если вам нравится:

public static bool Between(this DateTime compareDate, DateTime startDate, DateTime endDate) {
    return compareDate > startDate && compareDate < endDate;
}

тогда вы можете назвать это так:

if (Birthday.Between(DateRangeLower, DateRangeUpper) {
    // it's your birthday
}

Обновление : Если вы хотите игнорировать часть дня рождения, чтобы определить, находится ли годовщина даты в пределах диапазона, примените следующее:

if (DateRangeLower.DayOfYear <= DateRangeUpper.DayOfYear &&  
    Birthday.DayOfYear > DateRangeLower.DayOfYear && Birthday.DayOfYear < DateRangeUpper.DayOfYear) {
  // it's 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's your birthday
  //  note, we're actually checking to see if the date is outside of the
  //  original date's 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
}
1 голос
/ 31 марта 2010

Другой ответ, перенося все даты на определенный год.

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;
}
1 голос
/ 31 марта 2010

Я бы просто конвертировал все даты во время эпохи, а затем сделал бы прямое сравнение.

Я нашел это преобразование здесь , слегка изменено

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;
1 голос
/ 31 марта 2010

Суть вашей проблемы в том, чтобы выяснить, какой год назначить Дню рождения, чтобы убедиться, что вы можете выполнить сравнение допустимого диапазона.

У вас есть два случая, касающиеся диапазона, с которым вам нужно иметь дело:

  1. Нижняя граница имеет тот же год, что и верхняя граница
  2. Нижняя граница имеет год, отличный от верхней

РЕДАКТИРОВАТЬ: недостаточно кофе. Не обращайте внимания на мой предыдущий ответ.

Вам необходимо настроить даты в зависимости от месяца / дня дня рождения, который вы изучаете.

Вы не всегда можете использовать год с верхней границей, потому что день рождения может приходиться на месяц, который больше месяца с верхней границей. Одна простая альтернатива - выполнить проверку дважды: один раз, используя год с верхней границей, а затем снова, используя предыдущий год. Это обрабатывает случаи границ года:

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);
1 голос
/ 31 марта 2010

Вот мое решение. Он использует 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 ) );
1 голос
/ 31 марта 2010

Вы можете использовать свойство DayOfYear объектов DateTime.

if ((birthday.DayOfYear >= start.DayOfYear) && (birthday.DayOfYear <= end.DayOfYear)) {
  ...
}
0 голосов
/ 01 апреля 2010

Это должно правильно обрабатывать високосные годы:

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;
}
0 голосов
/ 31 марта 2010

Будет ли это работать !!!

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;  
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...