【问题标题】:How to determine if birthday or anniversary occurred during date range如何确定日期范围内是否发生生日或周年纪念日
【发布时间】:2011-02-02 23:08:09
【问题描述】:

鉴于我有一个生日/纪念日 DateTime,我如何确定该日期是否发生在特定日期范围内?例如,

生日 = 2000 年 1 月 2 日
日期范围 = 2008 年 12 月 25 日 - 2009 年 1 月 3 日

我需要一种方法来确定此人的生日是否在该日期范围内发生 - 最好是在 C# 中。

我首先着手更改生日 DateTime 的年份以匹配日期范围,然后检查“新”生日 DateTime 是否在日期范围的开始日期和结束日期之间......但是当日期范围跨越时不同的年份,就像我上面的例子一样——我不得不添加一个讨厌的 if 语句。有没有更好的办法?

【问题讨论】:

  • +1 因为这个问题比看起来要复杂得多!
  • 别忘了闰年会变得更加棘手:)
  • 其实闰年不会有任何区别:)
  • 同样重要的是不要忘记人们只有在实际出生后才庆祝生日。 :)

标签: c# datetime


【解决方案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'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
    }
    

    【讨论】:

    • 我认为您的意思是生日 = 和
    • 我不确定这是 OP 正在寻找的。他的情况涉及将生日值移入范围(基于年份),以查看它是在范围内还是在范围外。
    • 哎呀.. 好地方@Mongus。 @davekaro 可以通过更改为 >= 和
    • @LBushkin... 如果 OP 没有使用 DateTime 变量作为他的上限和下限,我鼓励他首先将他的变量解析为 DateTimes.. 然后使用这种方法。也许他正在寻找更复杂的东西!
    • 你不能这么轻易地忽略年份组件,这个解决方案不会告诉你出生于 2000 年 1 月 25 日的人的生日是否在 2008 年 1 月和 2 月之间,这就是他正在请求。
    【解决方案3】:

    更新答案以包括 SLC 提到的上限规范化。这应该适用于该人不是在 2002 年 2 月 29 日出生的情况。

    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;
    }
    

    【讨论】:

    • 我回来发布这个解决方案,这是这样做的方法,基本上将您的输入年份设置为与搜索的下限相同的年份。但是,在上述情况下,如果 bday 是 1983 10 5 并且范围是 1985 10 6 到 1986 10 10,那么您可能也必须为上限做这件事,因为 IF 将在标准化 >= min 部分失败。
    • 闰年会发生什么?例如,当birthday29/02/1984min01/10/2005?
    • 我认为这不适用于我在原始问题中提供的日期。使用我的日期,标准化日期将是 2008 年 1 月 2 日,这不是 >=“分钟”(2008 年 12 月 25 日)。
    • @Luke,闰年可能只是抛出一个异常。
    【解决方案4】:

    您可以使用 DateTime 对象的 DayOfYear 属性。

    if ((birthday.DayOfYear >= start.DayOfYear) && (birthday.DayOfYear <= end.DayOfYear)) {
      ...
    }
    

    【讨论】:

    • 如果范围是 01/11/2008 - 01/03/2009,这将失败。
    • true - 也许他的情况允许他使用这个 - 否则,看起来他又回到了一个讨厌的 if 语句。我认为 tanascius 的想法是正确的。
    • 如果这个人不是在被测试的范围之前出生的,这将失败。检查我的答案以获得可能的解决方案。
    【解决方案5】:

    问题的症结在于确定将哪一年分配给生日,以确保您可以执行有效的范围比较。

    您有两个与需要处理的范围相关的子案例:

    1. Lo​​werBound 与 UpperBound 的年份相同
    2. Lo​​werBound 与 UpperBound 的年份不同

    编辑:咖啡不够。忽略我之前的回答。

    您需要根据您检查的生日月份/日期调整日期。

    您不能总是使用上限年份,因为生日可能落在大于上限月份的月份。 一个简单的替代方法是执行两次检查:一次使用上限年份,然后再次使用前一年。这处理年份边界的情况:

    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);
    

    【讨论】:

    • 如果这个人出生在 2010 年,这仍然会说他的生日在那个范围内。我提供了一个可能的解决方案,首先只检查年份,然后将生日标准化以进行比较。
    • 您的 DateTime 构造函数错误。您的解决方案与 2000 年 12 月 26 日不匹配
    • 如果someBirthday29/02/2008upperBoundDate25/03/2009 会发生什么?
    • @João Angelo:我对那个有一点脑筋急转弯。你的观点是正确的,我已经调整了我的解决方案。
    【解决方案6】:

    这是我的解决方案。它使用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 ) );
    

    【讨论】:

    • 投反对票有什么理由吗?我想知道这段代码什么时候有错误。请发表评论
    【解决方案7】:

    我只是将所有日期转换为纪元时间,然后进行直接比较。

    我发现了这个转换here,稍作修改

    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...
        }
        

        【讨论】:

        • 等一下,我认为这是正确的答案,但事实并非如此 - 如果您的日期范围是 1 月 1 日到 3 月 3 日,并且您的生日是 2 月 6 日,则此代码将不起作用。跨度>
        • 不正确但很接近。您需要检查月份,并且只有在 Birthday.Month == DateRangeLower.Month 或 Birthday.Month == DateRangeUpper.Month 时才需要检查日期。
        【解决方案10】:

        你最好为此画一幅画。

        问题是从根本上确定是否存在这样的 N 使得该人的 N 岁生日在该范围内。

        您可以获取基线并使用模数进行天数计算,这将处理年份翻转(但闰年可能会导致差一错误)。

        另一个可能使表示更简单的替代方法是,由于生日在日历线上形成一维网格,因此如果生日不在该范围内,则该范围必须完全位于该人连续几年的生日之间: 即 NOT (BirthdayY1

        当我们做这种分析时,通常是整整几个月,所以找到 5 月的所有生日要简单得多,例如,获取生日贺卡。

        【讨论】:

          【解决方案11】:

          将生日设置为年份 = 2000,开始日期设置为年份 = 2000,结束日期设置为 2000 年。如果结束日期在开始日期之前,请将结束日期设置为年份2001.

          从上面的恶作剧之后:

          if (Birthday > DateRangeLower && Birthday < DateRangeUpper) {
              // it's 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;
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多