Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

asp.net - How would you calculate the age in C# using date of birth (considering leap years)

Here is a problem. I have seen many solutions, but no one seems to be fulfilling the criteria I want...

I want to display the age in this format

20 y(s) 2 m(s) 20 d(s)
20 y(s) 2 m(s)
2 m(s) 20 d(s)
20 d(s)

etc...

I have tried several solutions, but the leap year is causing the problem with me. My unit tests are always being failed because of leap years and no matter how many days come in between, the leap yeas count for extra number of days.

Here is my code....

public static string AgeDiscription(DateTime dateOfBirth)
{
    var today = DateTime.Now;
    var days = GetNumberofDaysUptoNow(dateOfBirth);
    var months = 0;
    var years = 0;
    if (days > 365)
    {
        years = today.Year - dateOfBirth.Year;
        days = days % 365;
    }
    if (days > DateTime.DaysInMonth(today.Year, today.Month))
    {
        months = Math.Abs(today.Month - dateOfBirth.Month);
        for (int i = 0; i < months; i++)
        {
            days -= DateTime.DaysInMonth(today.Year, today.AddMonths(0 - i).Month);
        }
    }

    var ageDescription = new StringBuilder("");

    if (years != 0)
        ageDescription = ageDescription.Append(years + " y(s) ");
    if (months != 0)
        ageDescription = ageDescription.Append(months + " m(s) ");
    if (days != 0)
        ageDescription = ageDescription.Append(days + " d(s) ");

    return ageDescription.ToString();
}

public static int GetNumberofDaysUptoNow(DateTime dateOfBirth)
{
    var today = DateTime.Now;
    var timeSpan = today - dateOfBirth;
    var nDays = timeSpan.Days;
    return nDays;
}

Any ideas???

UPDATE:

I want the difference between the two dates as:

var dateOfBirth = DateTime.Now.AddYears(-20);
string expected = "20 y(s) ";
string actual; // returns 20 y(s) 5 d(s)
actual = Globals.AgeDiscription(dateOfBirth);
Assert.AreEqual(expected, actual);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Age is pretty tricky. Here's the relevant excerpts from a struct I use.

public struct Age
{
    private readonly Int32 _years;
    private readonly Int32 _months;
    private readonly Int32 _days;
    private readonly Int32 _totalDays;

    /// <summary>
    /// Initializes a new instance of <see cref="Age"/>.
    /// </summary>
    /// <param name="start">The date and time when the age started.</param>
    /// <param name="end">The date and time when the age ended.</param>
    /// <remarks>This </remarks>
    public Age(DateTime start, DateTime end)
        : this(start, end, CultureInfo.CurrentCulture.Calendar)
    {
    }

    /// <summary>
    /// Initializes a new instance of <see cref="Age"/>.
    /// </summary>
    /// <param name="start">The date and time when the age started.</param>
    /// <param name="end">The date and time when the age ended.</param>
    /// <param name="calendar">Calendar used to calculate age.</param>
    public Age(DateTime start, DateTime end, Calendar calendar)
    {
        if (start > end) throw new ArgumentException("The starting date cannot be later than the end date.");

        var startDate = start.Date;
        var endDate = end.Date;

        _years = _months = _days = 0;
        _days += calendar.GetDayOfMonth(endDate) - calendar.GetDayOfMonth(startDate);
        if (_days < 0)
        {
            _days += calendar.GetDaysInMonth(calendar.GetYear(startDate), calendar.GetMonth(startDate));
            _months--;
        }
        _months += calendar.GetMonth(endDate) - calendar.GetMonth(startDate);
        if (_months < 0)
        {
            _months += calendar.GetMonthsInYear(calendar.GetYear(startDate));
            _years--;
        }
        _years += calendar.GetYear(endDate) - calendar.GetYear(startDate);

        var ts = endDate.Subtract(startDate);
        _totalDays = (Int32)ts.TotalDays;
    }

    /// <summary>
    /// Gets the number of whole years something has aged.
    /// </summary>
    public Int32 Years
    {
        get { return _years; }
    }

    /// <summary>
    /// Gets the number of whole months something has aged past the value of <see cref="Years"/>.
    /// </summary>
    public Int32 Months
    {
        get { return _months; }
    }

    /// <summary>
    /// Gets the age as an expression of whole months.
    /// </summary>
    public Int32 TotalMonths
    {
        get { return _years * 12 + _months; }
    }

    /// <summary>
    /// Gets the number of whole weeks something has aged past the value of <see cref="Years"/> and <see cref="Months"/>.
    /// </summary>
    public Int32 Days
    {
        get { return _days; }
    }

    /// <summary>
    /// Gets the total number of days that have elapsed since the start and end dates.
    /// </summary>
    public Int32 TotalDays
    {
        get { return _totalDays; }
    }

    /// <summary>
    /// Gets the number of whole weeks something has aged past the value of <see cref="Years"/> and <see cref="Months"/>.
    /// </summary>
    public Int32 Weeks
    {
        get { return (Int32) Math.Floor((Decimal) _days/7); }
    }

    /// <summary>
    /// Gets the age as an expression of whole weeks.
    /// </summary>
    public Int32 TotalWeeks
    {
        get { return (Int32) Math.Floor((Decimal) _totalDays/7); }
    }
}

Here's an example unit test that passes:

    [Test]
    public void Should_be_exactly_20_years_old()
    {
        var now = DateTime.Now;
        var age = new Age(now.AddYears(-20), now);

        Assert.That(age, Has.Property("Years").EqualTo(20)
            .And.Property("Months").EqualTo(0)
            .And.Property("Days").EqualTo(0));
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...