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


当前回答

我们是否需要考虑小于1岁的人?作为中国文化,我们将小婴儿的年龄描述为2个月或4周。

下面是我的实现,它不像我想象的那么简单,尤其是处理2/28这样的日期。

public static string HowOld(DateTime birthday, DateTime now)
{
    if (now < birthday)
        throw new ArgumentOutOfRangeException("birthday must be less than now.");

    TimeSpan diff = now - birthday;
    int diffDays = (int)diff.TotalDays;

    if (diffDays > 7)//year, month and week
    {
        int age = now.Year - birthday.Year;

        if (birthday > now.AddYears(-age))
            age--;

        if (age > 0)
        {
            return age + (age > 1 ? " years" : " year");
        }
        else
        {// month and week
            DateTime d = birthday;
            int diffMonth = 1;

            while (d.AddMonths(diffMonth) <= now)
            {
                diffMonth++;
            }

            age = diffMonth-1;

            if (age == 1 && d.Day > now.Day)
                age--;

            if (age > 0)
            {
                return age + (age > 1 ? " months" : " month");
            }
            else
            {
                age = diffDays / 7;
                return age + (age > 1 ? " weeks" : " week");
            }
        }
    }
    else if (diffDays > 0)
    {
        int age = diffDays;
        return age + (age > 1 ? " days" : " day");
    }
    else
    {
        int age = diffDays;
        return "just born";
    }
}

此实现已通过以下测试用例。

[TestMethod]
public void TestAge()
{
    string age = HowOld(new DateTime(2011, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2011, 11, 30), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2001, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("11 years", age);

    age = HowOld(new DateTime(2012, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("10 months", age);

    age = HowOld(new DateTime(2011, 12, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("11 months", age);

    age = HowOld(new DateTime(2012, 10, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2008, 2, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("11 months", age);

    age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 3, 28));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2009, 1, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
    Assert.AreEqual("1 month", age);

    // NOTE.
    // new DateTime(2008, 1, 31).AddMonths(1) == new DateTime(2009, 2, 28);
    // new DateTime(2008, 1, 28).AddMonths(1) == new DateTime(2009, 2, 28);
    age = HowOld(new DateTime(2009, 1, 31), new DateTime(2009, 2, 28));
    Assert.AreEqual("4 weeks", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 2, 28));
    Assert.AreEqual("3 weeks", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2012, 11, 5), new DateTime(2012, 11, 30));
    Assert.AreEqual("3 weeks", age);

    age = HowOld(new DateTime(2012, 11, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("4 weeks", age);

    age = HowOld(new DateTime(2012, 11, 20), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 week", age);

    age = HowOld(new DateTime(2012, 11, 25), new DateTime(2012, 11, 30));
    Assert.AreEqual("5 days", age);

    age = HowOld(new DateTime(2012, 11, 29), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 day", age);

    age = HowOld(new DateTime(2012, 11, 30), new DateTime(2012, 11, 30));
    Assert.AreEqual("just born", age);

    age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 2, 28));
    Assert.AreEqual("8 years", age);

    age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 3, 1));
    Assert.AreEqual("9 years", age);

    Exception e = null;

    try
    {
        age = HowOld(new DateTime(2012, 12, 1), new DateTime(2012, 11, 30));
    }
    catch (ArgumentOutOfRangeException ex)
    {
        e = ex;
    }

    Assert.IsTrue(e != null);
}

希望这有帮助。

其他回答

简单易懂的解决方案。

// Save today's date.
var today = DateTime.Today;

// Calculate the age.
var age = today.Year - birthdate.Year;

// Go back to the year in which the person was born in case of a leap year
if (birthdate.Date > today.AddYears(-age)) age--;

然而,这假设你在寻找西方的时代观念,而不是使用东亚的推算法。

我认为这个问题可以用这样一种更简单的方法解决-

该类可以是-

using System;

namespace TSA
{
    class BirthDay
    {
        double ageDay;
        public BirthDay(int day, int month, int year)
        {
            DateTime birthDate = new DateTime(year, month, day);
            ageDay = (birthDate - DateTime.Now).TotalDays; //DateTime.UtcNow
        }

        internal int GetAgeYear()
        {
            return (int)Math.Truncate(ageDay / 365);
        }

        internal int GetAgeMonth()
        {
            return (int)Math.Truncate((ageDay % 365) / 30);
        }
    }
}

电话可以是这样的-

BirthDay b = new BirthDay(1,12,1990);
int year = b.GetAgeYear();
int month = b.GetAgeMonth();

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

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;

我强烈建议使用名为AgeCalculator的NuGet软件包,因为在计算年龄(闰年、时间成分等)时需要考虑很多事情,而且只有两行代码不能削减它。该库给您的时间不只是一年。它甚至在计算时考虑了时间成分,这样你就可以得到一个包含年、月、日和时间成分的准确年龄。更为先进的是,可以选择将2月29日作为闰年,而将2月28日作为非闰年。