4

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);
Naveed Butt
  • 2,861
  • 6
  • 32
  • 55
  • possible duplicate of [How do I calculate someone's age in C#?](http://stackoverflow.com/questions/9/how-do-i-calculate-someones-age-in-c) – Magnus May 16 '12 at 12:15
  • This has been asked too many times, you didn't find any of them helpful ? – V4Vendetta May 16 '12 at 12:21
  • @V4Vendetta unfortunately, this has never been asked this way. I mean, the issue is something else, let me update my description... – Naveed Butt May 16 '12 at 12:30
  • 1
    @NaveedButt, how is your question different? – jrummell May 16 '12 at 12:39
  • 1
    @jrummell see the comment by HackedByChinese, he has made it quite clear, the difference between his and others' answers... My users need precise age – Naveed Butt May 16 '12 at 12:56
  • I understand the needs of @NaveedButt. The human concept of age is "fuzzy" compared to how a computer calculates it. If my birthday is today, and I'm 20 years old, then I would consider myself exactly 20 years old. A computer would say I'm actually 20.013698630137 years old. In many environments (medical, in my case), users need to be able to see how old they are, with said expectations, in years, months, and days (and weeks, in the case of infants). I'm not 20 years and 5 days old today, I'm 20 years old! So I agree, the other questions and answers out there are inadequate. – moribvndvs May 16 '12 at 13:07

6 Answers6

7

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));
    }
moribvndvs
  • 42,191
  • 11
  • 135
  • 149
  • so, would this return `20 y(s)`, when passed `start=DateTime.Now.AddYears(-20)` and `end=DateTime.Now`? I doubt it. I think it would return 20 y(s) 5 d(s) – Naveed Butt May 16 '12 at 12:26
  • Updated to include a unit test for your example. I wrote this for medical software, where users were very picky about how age is displayed (the approximations suggested in other answers are not adequate). – moribvndvs May 16 '12 at 12:39
2

Use

Timespan interval = DateTime.Now - DateOfBirth;

Then use

interval.Days
interval.TotalDays;
interval.Hours;
interval.TotalHours;
interval.Minutes;
interval.TotalMinutes;
interval.Seconds;
interval.TotalSeconds;
interval.Milliseconds;
interval.TotalMilliseconds;
interval.Ticks;

to get desired result.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
0
static int AgeInYears(DateTime birthday, DateTime today)
{
    return ((today.Year - birthday.Year) * 372 + (today.Month - birthday.Month) * 31 + (today.Day - birthday.Day)) / 372;
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • Age in years is not a problem. I want Age in Years, Months, Days – Naveed Butt May 16 '12 at 12:29
  • Doesn't really make sense though... Think about it - two people may be the exact same age in days, but when you convert it to years, months and days then the number of months and days part could differ depending on when the people were born. Someone born in February versus someone born in January, for example. – Matthew Watson May 16 '12 at 13:01
  • whether it makes sense or not, this is the user's requirement :( I am sorry, but thanks to @HackedByChinese I've got my answer :) – Naveed Butt May 16 '12 at 13:07
0

write this small function to have the number of leap year days between the current year and the date of birth year and add the returned days to the days part of your age:

 private static int NumberOfLeapYears(int startYear, int endYear)
 {         
 int counter = 0;
 for (int year = startYear; year <= endYear; year++)
 counter += DateTime.IsLeapYear(year) ? 1 : 0;
 return counter;
 } 
TRR
  • 1,637
  • 2
  • 26
  • 43
  • This would fail in case of a century year or a millenia year. This would only give the number of leap years and one will have to do a loop over the century years or millenia years as well and then put some more logic regarding overlapping century, millenia and leap years... – Naveed Butt Mar 21 '13 at 04:05
0

Check this code:

{                                                    
    dif = int(datediff("D", Convert.ToDateTime("01/" + Q101m.text + "/" + Q101y.Text), (Convert.ToDateTime(Vdate.text)))/365.25)

    //If dif < 15 Or dif > 49 
    {
           MessageBox.Show("xxxxxxx");
           Q101m.Focus();
    }

}
Prasad Jadhav
  • 5,090
  • 16
  • 62
  • 80
  • Welcome to StackOverflow! Your answer doesn't really address the question, or at least not very clearly. Have a read of http://stackoverflow.com/questions/how-to-answer – Tass Mar 21 '13 at 03:44
0

I created a solution as extension method in DateTime class which is 'derived' from @HackedByChinese:

    /// <summary>
    /// Calculate age in years relative to months and days, for example Peters age is 25 years 2 months and 10 days
    /// </summary>
    /// <param name="startDate">The date when the age started</param>
    /// <param name="endDate">The date when the age ended</param>
    /// <param name="calendar">Calendar used to calculate age</param>
    /// <param name="years">Return number of years, with considering months and days</param>
    /// <param name="months">Return calculated months</param>
    /// <param name="days">Return calculated days</param>
    public static bool GetAge(this DateTime startDate, DateTime endDate, Calendar calendar, out int years, out int months, out int days)
    {
        if (startDate > endDate)
        {
            years = months = days = -1;
            return false;
        }

        years = months = days = 0;
        days += calendar.GetDayOfMonth(endDate) - calendar.GetDayOfMonth(startDate);

        // When negative select days of last month
        if (days < 0)
        {
            days += calendar.GetDaysInMonth(calendar.GetYear(startDate), calendar.GetMonth(startDate));
            months--;
        }

        months += calendar.GetMonth(endDate) - calendar.GetMonth(startDate);

        // when negative select month of last year
        if (months < 0)
        {
            months += calendar.GetMonthsInYear(calendar.GetYear(startDate));
            years--;
        }

        years += calendar.GetYear(endDate) - calendar.GetYear(startDate);

        return true;
    }

But I recognized that the results days can differ a little bit from other calculators.

Galerion
  • 36
  • 3