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


当前回答

不知道为什么没有人尝试过:

        ushort age = (ushort)DateAndTime.DateDiff(DateInterval.Year, DateTime.Now.Date, birthdate);

它只需要使用Microsoft.VisualBasic;并引用项目中的此程序集(如果尚未引用)。

其他回答

这个经典问题值得野田时间来解决。

static int GetAge(LocalDate dateOfBirth)
{
    Instant now = SystemClock.Instance.Now;

    // The target time zone is important.
    // It should align with the *current physical location* of the person
    // you are talking about.  When the whereabouts of that person are unknown,
    // then you use the time zone of the person who is *asking* for the age.
    // The time zone of birth is irrelevant!

    DateTimeZone zone = DateTimeZoneProviders.Tzdb["America/New_York"];

    LocalDate today = now.InZone(zone).Date;

    Period period = Period.Between(dateOfBirth, today, PeriodUnits.Years);

    return (int) period.Years;
}

用法:

LocalDate dateOfBirth = new LocalDate(1976, 8, 27);
int age = GetAge(dateOfBirth);

您可能还对以下改进感兴趣:

将时钟作为IClock传递,而不是使用SystemClock.Instance,将提高可测试性。目标时区可能会更改,因此您也需要DateTimeZone参数。

另请参阅我关于这个主题的博客文章:处理生日和其他周年纪念日

我想添加希伯来文日历计算(或其他系统。全球化日历可以以相同的方式使用),使用此线程中的重写函数:

Public Shared Function CalculateAge(BirthDate As DateTime) As Integer
    Dim HebCal As New System.Globalization.HebrewCalendar ()
    Dim now = DateTime.Now()
    Dim iAge = HebCal.GetYear(now) - HebCal.GetYear(BirthDate)
    Dim iNowMonth = HebCal.GetMonth(now), iBirthMonth = HebCal.GetMonth(BirthDate)
    If iNowMonth < iBirthMonth Or (iNowMonth = iBirthMonth AndAlso HebCal.GetDayOfMonth(now) < HebCal.GetDayOfMonth(BirthDate)) Then iAge -= 1
    Return iAge
End Function

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

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中的代码在这里。

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

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

return sinceEpoch.Year - 1970;

人们可以这样计算“年龄”(即“西方人”的方式):

public static int AgeInYears(this System.DateTime source, System.DateTime target)
  => target.Year - source.Year is int age && age > 0 && source.AddYears(age) > target ? age - 1 : age < 0 && source.AddYears(age) < target ? age + 1 : age;

如果时间方向为“负”,则年龄也将为负。

可以添加一个分数,代表从目标到下一个生日的累计年龄:

public static double AgeInTotalYears(this System.DateTime source, System.DateTime target)
{
  var sign = (source <= target ? 1 : -1);

  var ageInYears = AgeInYears(source, target); // The method above.

  var last = source.AddYears(ageInYears);
  var next = source.AddYears(ageInYears + sign);

  var fractionalAge = (double)(target - last).Ticks / (double)(next - last).Ticks * sign;

  return ageInYears + fractionalAge;
}

分数是过去的时间(从上一个生日到下一个生日)与总时间的比率。

无论是向前还是向后,这两种方法都以相同的方式工作。