anyone know how to get the age based on a date(birthdate)
im thinking of something like this
string age = DateTime.Now.GetAccurateAge();
My answer is not exactly an answer; it is a way to find an answer in this and similar threads. The correct answer has already been provided by LukeH, and my 2 cents here is for anyone that want to know which is the more correct answer*.
*more correct because, as you saw in several discussions and comments scattered around, we have to compromise with some preconditions in leap years - dob is 1-mar or 28-feb in normal years?
I'm using as benchmark this and this other sites that do that, and my brain too ;)
I implemented LukeH, @Panos Theof and @xr280xr answers here:
public static class DateTimeExtensions
{
public static int HowOld(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//https://stackoverflow.com/a/3055445/2752308
//LukeH: essentially right
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (dayToCalculate.Day < initialDay.Day)
{
months--;
}
if (months < 0)
{
years--;
months += 12;
}
days = (dayToCalculate - initialDay.AddMonths((years * 12) + months)).Days;
Console.WriteLine(
$"{years} year{((years == 1) ? "" : "s")}, {months} month{((months == 1) ? "" : "s")} and {days} day{((days == 1) ? "" : "s")}");
return years;
}
public static int HowOld2(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//@Panos Theof: wrong
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (dayToCalculate.Day < initialDay.Day)
{
dayToCalculate = dayToCalculate.AddMonths(-1);
}
if (months < 0)
{
dayToCalculate = dayToCalculate.AddYears(-1);
months += 12;
}
years = dayToCalculate.Year - initialDay.Year;
var offs = initialDay.AddMonths(years * 12 + months);
days = (int)((dayToCalculate.Ticks - offs.Ticks) / TimeSpan.TicksPerDay);
Console.WriteLine(
$"{years} year{((years == 1) ? "" : "s")}, {months} month{((months == 1) ? "" : "s")} and {days} day{((days == 1) ? "" : "s")}");
return years;
}
public static int HowOld3(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//@xr280xr: wrong
//Get the relative difference between each date part
days = dayToCalculate.Day - initialDay.Day;
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (days < 0)
{
days = DateTime.DaysInMonth(initialDay.Year, initialDay.Month) - initialDay.Day + //Days left in month of birthday +
dayToCalculate.Day; //Days passed in dayToCalculate's month
months--; //Subtract incomplete month that was already counted
}
if (months < 0)
{
months += 12; //Subtract months from 12 to convert relative difference to # of months
years--; //Subtract incomplete year that was already counted
}
Console.WriteLine(string.Format("{0} year{1}, {2} month{3} and {4} day{5}",
years, (years == 1) ? "" : "s",
months, (months == 1) ? "" : "s",
days, (days == 1) ? "" : "s"));
return years;
}
}
Using VS2019 and XUnit I create an Inlinedata generator Class:
public class CalculatorTestData : IEnumerable
And setup for the three methods:
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld(DateTime initialDay, DateTime dayToCalculate,int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//LukeH: essentially right
int resultMonths, resultDays;
int age = initialDay.HowOld(dayToCalculate,out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld2(DateTime initialDay, DateTime dayToCalculate, int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//@Panos Theof: wrong
int resultMonths, resultDays;
int age = initialDay.HowOld2(dayToCalculate, out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld3(DateTime initialDay, DateTime dayToCalculate, int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//@xr280xr: wrong
int resultMonths, resultDays;
int age = initialDay.HowOld3(dayToCalculate, out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
The expected results are on the InlineData Class, of course.
The output results are:
So, LukeH has the correct answer. And, for my surprise, both sites disagree for leap DOB, and IMHO Calculator.net is correct, and timeanddate.com plainly wrong, producing this error outputs:
For DOB Feb 29:
both 28/02 and 29/02 produce 52, 0, 0 (?!)
01/03 yields 52, 0, 2 (!!!???)
Feb 29, 2016 => Feb 28, 2017 => 1 y, 0 m, 1 d (!!!???)
Hope showing the test setup helps someone.