【问题标题】:Determine if it has been 6 months since birthday in c#在c#中确定生日是否已经6个月
【发布时间】:2010-04-29 15:13:06
【问题描述】:

如果客户上一个生日已经过去 6 个月,我的应用程序需要将客户当前年龄调整 +0.5。

代码应该是这样的,但是 6 个月内会有多少滴答声?

if (DateTime.Today - dateOfBirth.Date > new TimeSpan(6))
        {
            adjust = 0.5M;
        }
        else
        {
            adjust = 0M;
        }

提前致谢

【问题讨论】:

  • 希望你的 dateOfBirth 没有他们的实际出生年份...
  • 您向客户支付的费用是多少?
  • dateOfBirth 是否标准化为当前年份?
  • 这样一个简单的问题引起了如此多的错误反应......这对编程的未来来说并不是一个好兆头

标签: c# datetime datediff


【解决方案1】:

编辑:你知道吗?既然很清楚你真正需要的只是将用户的年龄显示在 6 个月内,那么这就是你真正应该做的。

static decimal GetApproximateAge(DateTime dateOfBirth) {
    TimeSpan age = DateTime.Now - dateOfBirth;

    /* a note on the line below:
     * treating 182.5 days as equivalent to 6 months,
     * reasoning that this will provide acceptable accuracy
     * for ages below ~360 years
     * 
     * (result will be 1 day off for roughly every 4 years;
     * for a calculation of half-years to be inaccurate
     * would take 4 [years] * ~90 [days] = ~360)
     */

    // get age in units of 6 months
    // desired behavior is not to add 0.5 until
    // a full six months have elapsed since the user's last birthday --
    // using Math.Floor to ensure this
    double approxAgeInHalfYears = Math.Floor(age.TotalDays / 182.5);

    // now convert this to years
    // did it this way to restrict age to increments of 0.5
    double approxAgeInYears = approxAgeInHalfYears * 0.5;

    return Convert.ToDecimal(approxAgeInYears);
}

上面的代码包含一个大注释,解释了它自己的缺点,David 很有帮助地指出。

现在,还有另一个选项。这有点难看,因为它使用了循环;但它也更加坚如磐石,因为它使用了 DateTime.AddMonths 方法,该方法的优点是已经过 Microsoft 的测试和记录。

static decimal GetApproximateAge(DateTime dateOfBirth) {
    DateTime now = DateTime.Now;

    int birthYear = dateOfBirth.Year;
    int lastYear = now.Year - 1;

    // obviously, if the user's alive, he/she had a birthday last year;
    // therefore he/she is at least this old
    int minimumAgeInYears = lastYear - birthYear;

    // now the question is: how much time has passed since then?
    double actualAgeInYears = (double)minimumAgeInYears;

    // for every six months that have elapsed since the user's birthday
    // LAST year, add 0.5 to his/her age
    DateTime birthDateLastYear = new DateTime(lastYear, 1, 1)
        .AddDays(dateOfBirth.DayOfYear);

    DateTime comparisonDate = birthDateLastYear
        .AddMonths(6);

    while (comparisonDate < now) {
        actualAgeInYears += 0.5;
        comparisonDate = comparisonDate.AddMonths(6);
    }

    return Convert.ToDecimal(actualAgeInYears);
}

人们一直建议检查dateOfBirth.AddMonths(6) 的想法是错误。由于dateOfBirth 是一个DateTime,它代表的是用户的出生date,而不是他们的出生day

您要检查的是自用户的上一次生日(而不是他们的出生日期)是否已经过去了六个月。这是一种方法:

DateTime lastBirthDay = GetLastBirthday(dateOfBirth);

if (DateTime.Today > lastBirthDay.AddMonths(6))
{
    adjust = 0.5M;
}
else
{
    adjust = 0M;
}

DateTime GetLastBirthday(DateTime dateOfBirth)
{
    int currentYear = DateTime.Now.Year;
    int birthMonth = dateOfBirth.Month;
    int birthDay = dateOfBirth.Day;

    // if user was born on Feb 29 and this year is NOT a leap year,
    // we'll say the user's birthday this year falls on Feb 28
    if (birthMonth == 2 && birthDay == 29 && !IsLeapYear(currentYear))
        birthDay = 28;

    DateTime birthdayThisYear = new DateTime(
        currentYear,
        birthMonth,
        birthDay
    );

    if (DateTime.Today > birthdayThisYear)
        return birthdayThisYear;
    else
        return birthdayThisYear.AddYears(-1);
}

bool IsLeapYear(int year) {
    return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
}

【讨论】:

  • 感谢 Dan,您发布了一些非常有用的信息
  • 您已部分修复了 2 月 29 日的错误,但仍然存在 Lotus 1-2-3 闰年错误:您假设 any 年可被 4 整除是闰年,这些年份使用 2 月 29 日。能被 100 整除的年份不是闰年,除非它们也能被 400 整除。这意味着 1900 年 2 月 29 日将抛出一个参数异常(并且出生日期确实出现了,我不得不使用 Lotus/Excel(Excel 使用向后兼容的 Lotus 日期)不喜欢 1890 年代出生的 在世 客户)。
  • @David:哈,哇,老实说,我什至不知道闰年。感谢您指出。 (顺便说一句,对于它的价值,我没有否决你的答案。)
  • 我喜欢你的新解决方案(它触及了问题的核心),但我认为其中也存在闰年错误。随着人年龄的增长,未考虑的闰日数会迅速增加(您已采用 365/2)。改用 182.625 (365.25/2) 会更好(也许使用 Floor 而不是 Round),这样一个 40 岁的人在计算中就没有 10 个未计入的天数吗?除非该程序旨在计算死者(历史),否则由于 100/400 年跳跃导致的偏差应该四舍五入。
  • @Dan Tao 我和​​其他人一样开枪,并根据似乎是直接问题(如何获得 6 个月的时间段)来回答,而没有看到提出的整个概念有缺陷,所以downvotes都是合理的。具有讽刺意味的是,我仍然获得了相当不错的净声誉,因为那些反对票太少了。至少它可以正确地对页面上的答案进行排序。
【解决方案2】:

为什么不改为if (dateOfBirth.Date.AddMonths(6) &lt; DateTime.Today)

【讨论】:

  • 您是否意识到假设该人至少六个月大,这将始终返回 true?
  • 非常好。我想我正忙着试图忽略这样一个事实,即指定的代码会将年龄调整 0.5,无论这是否是正确的数量(我们不知道测试是在生日后 6 个月完成的,真的是 6 个月正好半年)或者如果之前已经完成了增量。从其他答案看来,这种失明并不少见。也许我应该用更正确的方式编辑答案(当然这意味着我需要处理 2 月 29 日的 DoB - 我们想要自去年 2 月 29 日起 6 个月,还是自 2 月 28 日或 3 月 1 日起 6 个月?)跨度>
  • 抱歉,我应该提到这是我最近感兴趣的人的生日。现在更新我的问题
  • 2 月 29 日的好电话。我在冗长的回答中添加了一个检查。
【解决方案3】:
        long ticks = new DateTime(0).AddMonths(6).Ticks;
        TimeSpan ts = new TimeSpan(ticks);

【讨论】:

    【解决方案4】:
    if (dateOfBirth.Date.AddMonths(6) < DateTime.Today)
    {
       age += 0.5;
    }
    

    【讨论】:

    • 如果您超过六个月大,这也总是正确的。
    【解决方案5】:

    我认为你可能过于复杂了:

    DateTime displayDate = User.BirthDate; // User.BirthDate is a mock for however you get the birth date
    
    if(DateTime.Now.AddMonths(-6) > displayDate)
    {
        // More than 6 Months have passed, so perform your logic to add .5 years
    }
    

    【讨论】:

      【解决方案6】:

      这样的?

      if (DateTime.Now.AddMonths(-6) > dateofBirth.Date)
      {
          dateOfBirth = dateOfBirth.AddMonths(6);
      }
      

      【讨论】:

      • dateOfBirth.AddMonths(6); 什么都不做。它只是返回一个值。
      • @Germ: DateTime 是不可变的,你不能改变它,你必须这样做dateOfBirth = dateOfBirth.AddMonths(6)
      • 还是不行。就像大卫的回答一样,只要用户至少六个月大,这将为dateOfBirth 添加六个月。另外,我认为这个想法是在用户的 age 上加上 0.5,而不是他们的生日!
      【解决方案7】:

      我想你实际上想知道他们上一个生日是否是半年而不是六个月(因为月份的长度不同)。

          int daysDiff = DateTime.Now.DayOfYear - dayofBirth.DayOfYear;
          if (daysDiff <0) daysDiff += 365;
          double adjust = daysDiff > 365/2 ? 0.5 : 0.0;
      

      【讨论】:

        【解决方案8】:
        DateTime today = DateTime.Today;
        DateTime lastBirthday = dateOfBirth.Date.AddYears(today.Year - dateOfBirth.Year);
        if (lastBirthday > today) lastBirthday = lastBirthday.AddYears(-1);
        
        if (today > lastBirthday.AddMonths(6))
            adjust = 0.5M;
        else
            adjust = 0M;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-28
          • 1970-01-01
          • 2017-08-08
          • 2011-05-18
          • 1970-01-01
          • 2016-06-21
          相关资源
          最近更新 更多