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


当前回答

private int GetYearDiff(DateTime start, DateTime end)
{
    int diff = end.Year - start.Year;
    if (end.DayOfYear < start.DayOfYear) { diff -= 1; }
    return diff;
}
[Fact]
public void GetYearDiff_WhenCalls_ShouldReturnCorrectYearDiff()
{
    //arrange
    var now = DateTime.Now;
    //act
    //assert
    Assert.Equal(24, GetYearDiff(new DateTime(1992, 7, 9), now)); // passed
    Assert.Equal(24, GetYearDiff(new DateTime(1992, now.Month, now.Day), now)); // passed
    Assert.Equal(23, GetYearDiff(new DateTime(1992, 12, 9), now)); // passed
}

其他回答

我创建了一个Age结构,如下所示:

public struct Age : IEquatable<Age>, IComparable<Age>
{
    private readonly int _years;
    private readonly int _months;
    private readonly int _days;

    public int Years  { get { return _years; } }
    public int Months { get { return _months; } }
    public int Days { get { return _days; } }

    public Age( int years, int months, int days ) : this()
    {
        _years = years;
        _months = months;
        _days = days;
    }

    public static Age CalculateAge( DateTime dateOfBirth, DateTime date )
    {
        // Here is some logic that ressembles Mike's solution, although it
        // also takes into account months & days.
        // Ommitted for brevity.
        return new Age (years, months, days);
    }

    // Ommited Equality, Comparable, GetHashCode, functionality for brevity.
}

非常简单的答案

        DateTime dob = new DateTime(1991, 3, 4); 
        DateTime now = DateTime.Now; 
        int dobDay = dob.Day, dobMonth = dob.Month; 
        int add = -1; 
        if (dobMonth < now.Month)
        {
            add = 0;
        }
        else if (dobMonth == now.Month)
        {
            if(dobDay <= now.Day)
            {
                add = 0;
            }
            else
            {
                add = -1;
            }
        }
        else
        {
            add = -1;
        } 
        int age = now.Year - dob.Year + add;

这是我们在这里使用的版本。它有效,而且相当简单。这与Jeff的想法相同,但我认为它更清晰一点,因为它分离了减法的逻辑,所以更容易理解。

public static int GetAge(this DateTime dateOfBirth, DateTime dateAsAt)
{
    return dateAsAt.Year - dateOfBirth.Year - (dateOfBirth.DayOfYear < dateAsAt.DayOfYear ? 0 : 1);
}

如果你认为这类事情不清楚,你可以扩展三元运算符使其更清晰。

显然,这是作为DateTime上的一个扩展方法完成的,但很明显,您可以抓取一行代码来完成工作并将其放在任何位置。这里我们有另一个传入DateTime的Extension方法重载。

这是一个非常适合我的功能。没有计算,非常简单。

    public static string ToAge(this DateTime dob, DateTime? toDate = null)
    {
        if (!toDate.HasValue)
            toDate = DateTime.Now;
        var now = toDate.Value;

        if (now.CompareTo(dob) < 0)
            return "Future date";

        int years = now.Year - dob.Year;
        int months = now.Month - dob.Month;
        int days = now.Day - dob.Day;

        if (days < 0)
        {
            months--;
            days = DateTime.DaysInMonth(dob.Year, dob.Month) - dob.Day + now.Day;
        }

        if (months < 0)
        {
            years--;
            months = 12 + months;
        }


        return string.Format("{0} year(s), {1} month(s), {2} days(s)",
            years,
            months,
            days);
    }

这里是一个单元测试:

    [Test]
    public void ToAgeTests()
    {
        var date = new DateTime(2000, 1, 1);
        Assert.AreEqual("0 year(s), 0 month(s), 1 days(s)", new DateTime(1999, 12, 31).ToAge(date));
        Assert.AreEqual("0 year(s), 0 month(s), 0 days(s)", new DateTime(2000, 1, 1).ToAge(date));
        Assert.AreEqual("1 year(s), 0 month(s), 0 days(s)", new DateTime(1999, 1, 1).ToAge(date));
        Assert.AreEqual("0 year(s), 11 month(s), 0 days(s)", new DateTime(1999, 2, 1).ToAge(date));
        Assert.AreEqual("0 year(s), 10 month(s), 25 days(s)", new DateTime(1999, 2, 4).ToAge(date));
        Assert.AreEqual("0 year(s), 10 month(s), 1 days(s)", new DateTime(1999, 2, 28).ToAge(date));

        date = new DateTime(2000, 2, 15);
        Assert.AreEqual("0 year(s), 0 month(s), 28 days(s)", new DateTime(2000, 1, 18).ToAge(date));
    }

我认为TimeSpan包含了我们所需要的一切,而不必求助于365.25(或任何其他近似值)。扩展Aug的示例:

DateTime myBD = new DateTime(1980, 10, 10);
TimeSpan difference = DateTime.Now.Subtract(myBD);

textBox1.Text = difference.Years + " years " + difference.Months + " Months " + difference.Days + " days";