给定代表某人生日的DateTime,我如何计算他们的年龄(以年为单位)?


当前回答

只需使用:

(DateTime.Now - myDate).TotalHours / 8766.0

当前日期-myDate=TimeSpan,获取总小时数并除以每年的总小时数,得到确切的年龄/月/日。。。

其他回答

以下是使用DateTimeOffset和手动数学的答案:

var diff = DateTimeOffset.Now - dateOfBirth;
var sinceEpoch = DateTimeOffset.UnixEpoch + diff;

return sinceEpoch.Year - 1970;

2需要解决的主要问题有:

1.计算准确年龄-以年、月、日等为单位。

2.计算人们普遍认为的年龄——人们通常不关心自己到底多大,他们只关心自己当年的生日是什么时候。


1的解决方案显而易见:

DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today;     //we usually don't care about birth time
TimeSpan age = today - birth;        //.NET FCL should guarantee this as precise
double ageInDays = age.TotalDays;    //total number of days ... also precise
double daysInYear = 365.2425;        //statistical value for 400 years
double ageInYears = ageInDays / daysInYear;  //can be shifted ... not so precise

2的解决方案在确定总年龄时并不那么精确,但人们认为它是精确的。当人们“手动”计算年龄时,通常也会使用它:

DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today;
int age = today.Year - birth.Year;    //people perceive their age in years

if (today.Month < birth.Month ||
   ((today.Month == birth.Month) && (today.Day < birth.Day)))
{
  age--;  //birthday in current year not yet reached, we are 1 year younger ;)
          //+ no birthday for 29.2. guys ... sorry, just wrong date for birth
}

注释2.:

这是我的首选解决方案我们不能使用DateTime.DayOfYear或TimeSpans,因为它们会在闰年中改变天数为了可读性,我只增加了几行

还有一个提示。。。我将为它创建两个静态重载方法,一个用于通用,另一个用于使用友好:

public static int GetAge(DateTime bithDay, DateTime today) 
{ 
  //chosen solution method body
}

public static int GetAge(DateTime birthDay) 
{ 
  return GetAge(birthDay, DateTime.Now);
}

我找到的最简单的方法就是这样。它适用于美国和西欧地区。无法与其他地区通话,尤其是中国这样的地方。在最初计算年龄后,最多可额外进行4次比较。

public int AgeInYears(DateTime birthDate, DateTime referenceDate)
{
  Debug.Assert(referenceDate >= birthDate, 
               "birth date must be on or prior to the reference date");

  DateTime birth = birthDate.Date;
  DateTime reference = referenceDate.Date;
  int years = (reference.Year - birth.Year);

  //
  // an offset of -1 is applied if the birth date has 
  // not yet occurred in the current year.
  //
  if (reference.Month > birth.Month);
  else if (reference.Month < birth.Month) 
    --years;
  else // in birth month
  {
    if (reference.Day < birth.Day)
      --years;
  }

  return years ;
}

我仔细查看了答案,发现没有人提及闰日出生的监管/法律影响。例如,根据维基百科,如果你在2月29日出生在不同的司法管辖区,你的非闰年生日会有所不同:

在英国和香港:这是一年中的第几天,所以第二天,3月1日是你的生日。在新西兰:这是前一天,2月28日用于驾驶执照,3月1日用于其他目的。台湾:今天是2月28日。

据我所知,在美国,法规对此事保持沉默,这取决于普通法以及各个监管机构如何在其法规中定义事物。

为此,需要改进:

public enum LeapDayRule
{
  OrdinalDay     = 1 ,
  LastDayOfMonth = 2 ,
}

static int ComputeAgeInYears(DateTime birth, DateTime reference, LeapYearBirthdayRule ruleInEffect)
{
  bool isLeapYearBirthday = CultureInfo.CurrentCulture.Calendar.IsLeapDay(birth.Year, birth.Month, birth.Day);
  DateTime cutoff;

  if (isLeapYearBirthday && !DateTime.IsLeapYear(reference.Year))
  {
    switch (ruleInEffect)
    {
      case LeapDayRule.OrdinalDay:
        cutoff = new DateTime(reference.Year, 1, 1)
                             .AddDays(birth.DayOfYear - 1);
        break;

      case LeapDayRule.LastDayOfMonth:
        cutoff = new DateTime(reference.Year, birth.Month, 1)
                             .AddMonths(1)
                             .AddDays(-1);
        break;

      default:
        throw new InvalidOperationException();
    }
  }
  else
  {
    cutoff = new DateTime(reference.Year, birth.Month, birth.Day);
  }

  int age = (reference.Year - birth.Year) + (reference >= cutoff ? 0 : -1);
  return age < 0 ? 0 : age;
}

需要注意的是,该代码假设:

西方(欧洲)对年龄的推算,以及一种日历,如公历,在月底插入一个闰日。

我经常用手指数。我需要看一下日历,以确定事情何时发生变化。这就是我在代码中要做的:

int AgeNow(DateTime birthday)
{
    return AgeAt(DateTime.Now, birthday);
}

int AgeAt(DateTime now, DateTime birthday)
{
    return AgeAt(now, birthday, CultureInfo.CurrentCulture.Calendar);
}

int AgeAt(DateTime now, DateTime birthday, Calendar calendar)
{
    // My age has increased on the morning of my
    // birthday even though I was born in the evening.
    now = now.Date;
    birthday = birthday.Date;

    var age = 0;
    if (now <= birthday) return age; // I am zero now if I am to be born tomorrow.

    while (calendar.AddYears(birthday, age + 1) <= now)
    {
        age++;
    }
    return age;
}

在LINQPad中运行此过程可获得以下结果:

PASSED: someone born on 28 February 1964 is age 4 on 28 February 1968
PASSED: someone born on 29 February 1964 is age 3 on 28 February 1968
PASSED: someone born on 31 December 2016 is age 0 on 01 January 2017

LINQPad中的代码在这里。

SQL版本:

declare @dd smalldatetime = '1980-04-01'
declare @age int = YEAR(GETDATE())-YEAR(@dd)
if (@dd> DATEADD(YYYY, -@age, GETDATE())) set @age = @age -1

print @age