anyone know how to get the age based on a date(birthdate)
im thinking of something like this
string age = DateTime.Now.GetAccurateAge();
and the output will be some thing like 20Years 5Months 20Days
anyone know how to get the age based on a date(birthdate)
im thinking of something like this
string age = DateTime.Now.GetAccurateAge();
and the output will be some thing like 20Years 5Months 20Days
public static class DateTimeExtensions
{
public static string ToAgeString(this DateTime dob)
{
DateTime today = DateTime.Today;
int months = today.Month - dob.Month;
int years = today.Year - dob.Year;
if (today.Day < dob.Day)
{
months--;
}
if (months < 0)
{
years--;
months += 12;
}
int days = (today - dob.AddMonths((years * 12) + months)).Days;
return string.Format("{0} year{1}, {2} month{3} and {4} day{5}",
years, (years == 1) ? "" : "s",
months, (months == 1) ? "" : "s",
days, (days == 1) ? "" : "s");
}
}
See the answers at How do I calculate someone’s age in C#? for ideas.
Not certain that it would always be correct (haven't thought about if there's some cases with leap years etc that might make it fail...), but this is an easy way to get out the year and month:
DateTime bd = DateTime.Parse("2009-06-17");
TimeSpan ts = DateTime.Now.Subtract(bd);
DateTime age = DateTime.MinValue + ts;
string s = string.Format("{0} Years {1} months {2} days", age.Year -1 , age.Month - 1, age.Day - 1);
Since i can't post code to a comment, here it is the code based on @LukeH answer, with the bug fixed
public static int GetAge( DateTime dob, DateTime today, out int days, out int months ) {
DateTime dt = today;
if( dt.Day < dob.Day ) {
dt = dt.AddMonths( -1 );
}
months = dt.Month - dob.Month;
if( months < 0 ) {
dt = dt.AddYears( -1 );
months += 12;
}
int years = dt.Year - dob.Year;
var offs = dob.AddMonths( years * 12 + months );
days = (int)( ( today.Ticks - offs.Ticks ) / TimeSpan.TicksPerDay );
return years;
}
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<object[]>
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 26), 53, 11, 29 };
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 27), 54, 0, 0 };
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 28), 54, 0, 1 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 2, 28), 51, 11, 30 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 2, 29), 52, 0, 0 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 3, 01), 52, 0, 1 };
yield return new object[] { new DateTime(2016, 2, 29), new DateTime(2017, 2, 28), 0, 11, 30 };
}
IEnumerator<object[]> IEnumerable<object[]>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
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.
This is what I use. It's a combination of the selected answer and this answer.
For someone born on 2016-2-29, on the 2017-3-1 their age outputs:
Years: 1
Months: 1 (28 days for February)
Days: 0
var today = new DateTime(2020,11,4);
//var today = DateTime.Today;
// Calculate the age.
var years = today.Year - dateOfBirth.Year;
// Go back to the year in which the person was born in case of a leap year
if (dateOfBirth.Date > today.AddYears(-years))
{
years--;
}
var months = today.Month - dateOfBirth.Month;
// Full month hasn't completed
if (today.Day < dateOfBirth.Day)
{
months--;
}
if (months < 0)
{
months += 12;
}
Years = years;
Months = months;
Days = (today - dateOfBirth.AddMonths((years * 12) + months)).Days;
Here is what I use:
public static int GetAge(DateTime dateOfBirth)
{
int age = DateTime.Now.Year - dateOfBirth.Year;
if (dateOfBirth.AddYears(age) > DateTime.Now)
{
age = age - 1;
}
return age;
}
This sounds like a fine exercise to get to know the TimeSpan class better.
@if (Model.CF_DateOfBirth.HasValue)
{
var today = DateTime.Today;
var months = DateTime.Today;
var age = today.Year - Model.CF_DateOfBirth.Value.Year;
var mons = months.Month - Model.CF_DateOfBirth.Val`enter code here`ue.Month;
if (Model.CF_DateOfBirth > today.AddYears(-age) && Model.CF_DateOfBirth>months.AddMonths(-mons))
{
age--; mons--;
}
<i class="" style="color:cadetblue"> Date of birth: </i><b style="color:teal">@Convert.ToDateTime(Model.CF_DateOfBirth).ToShortDateString().ToString()</b> <span> ( <b>@age</b>Years <b>@mons</b> Months)</span>
}
I find this the most accurate.
private int GetAge(DateTime birthDate)
{
TimeSpan ageTimeSpan = DateTime.UtcNow.Subtract(birthDate);
int age = new DateTime(ageTimeSpan.Ticks).Year;
return age;
}
I was noticing peculiarities with LukeH's answer and leap years. The simplest example is probably a dob = 2/29/2016 as of 2/28/2017 and 3/1/2017. The way I look at it, there are no days left in Feb 2016, there are 11 complete months (Mar-Jan) in between, and there have been 28 days in Feb 2017 so far, so as of 2/28/2017, I would call this person 11 months 28 days old. And 1 year 1 day old as of 3/1/2017. (Although some leap day babies do celebrate and on the 28th of common years ... I'm curious what the legal consideration is.)
Because LukeH's method makes uses of DateTime.AddMonths, it calculates 11 months 30 days, because it finds the difference in days between 2/28/2017 and 1/29/2017. So it calculates that 2/28/2017 is 11 mo 30 days after 2/29/2016, and 11 mo 27 days after 3/1/2016. A 3 day age difference for birthdays only 1 day apart. If it came up with 28 days as I did "by hand" they would have a one day age difference.
I'm not exactly sure how to describe the fundamental difference in approaches, but here is my stab at it. It seems there is always a gotcha with dates so please scrutinize.
internal static void CalculateAge(DateTime dateOfBirth, DateTime asOfDate, out int years, out int months, out int days)
{
Console.Write("As of " + asOfDate.ToShortDateString() + ": ");
//Get the relative difference between each date part
days = asOfDate.Day - dateOfBirth.Day;
months = asOfDate.Month - dateOfBirth.Month;
years = asOfDate.Year - dateOfBirth.Year;
if (days < 0)
{
days = DateTime.DaysInMonth(dateOfBirth.Year, dateOfBirth.Month) - dateOfBirth.Day + //Days left in month of birthday +
asOfDate.Day; //Days passed in asOfDate'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"));
}
If you have a Instance Variable/Property that names DateOfBirth, you can use this method. Otherwise, you can pass the Date of Birth as a parameter for method. I made some calculus and I proved that never fails.
public int AgeCalc(){
DateTime now = DateTime.Now;
double age = Math.Floor((DateTime.Now - DateOfBirth).TotalDays)/((DateTime.IsLeapYear(year: now.Year)? 366 : 365));
return (age % 1) >= 0.951 ? Math.Round(age) : Math.Floor(age);
}
I hope that this can help you :)
I wanted this down to the second and hence came up with something a little more precise (and perhaps slightly overengineered).
This uses reflection to pull the fields from the DateTime object and then iterate over each field provided, calculating the correct amount to use for the relevant unit.
/// <summary>
/// For calculating age
/// </summary>
/// <param name="dob">Date of birth</param>
/// <returns>Age in text format</returns>
public static string CalculateAge(DateTime dob)
{
// Initialise now and list of properties to retrieve for calculating age
var now = DateTime.Now;
var propertyNames = new List<string>()
{
"Second",
"Minute",
"Hour",
"Day",
"Month",
"Year"
};
// Get the properties and order them in accordance to smallest unit
// Important to do so as you perform standard subtraction starting with the smallest unit
var properties = typeof(DateTime)
.GetProperties()
.Where(x => propertyNames.Contains(x.Name))
.OrderBy(x => propertyNames.FindIndex(y => y == x.Name));
// Create string builder to build age as a string
var returnVal = new StringBuilder();
foreach(var property in properties)
{
// Calculate the amount for the current property
var amount = (int)property.GetValue(now) - (int)property.GetValue(dob);
if (amount < 0)
switch(property.Name)
{
case "Month":
amount += 12;
dob = dob.AddYears(-1);
break;
case "Day":
amount += DateTime.DaysInMonth(dob.Year, dob.Month);
dob = dob.AddMonths(-1);
break;
case "Hour":
amount += 24;
dob = dob.AddDays(-1);
break;
case "Minute":
amount += 60;
dob = dob.AddHours(-1);
break;
case "Second":
amount += 60;
dob = dob.AddMinutes(-1);
break;
}
// Write to the stringbuilder
returnVal.Insert(0, property.Name + "s: " + amount + ", ");
}
// Trim final ', ' at the end
return returnVal.ToString().TrimEnd().TrimEnd(',');
}
This allows you to go to any precision you want (if you want the year to be correct in terms of western culture for calculating age, you'll want to be at least as precise as the day)
Also I've just manually initialised the list at the start, but you can of course make this configurable if that's what your solution requires, but specifically the list must be ordered from the lowest unit to the highest unit (and the values must specifically refer to the property names for DateTime). If you want to validate this in the worrying case the config value is set to a list in the wrong order, you can initialise a list with ALL the DateTime fields, then pull your configurable list, and use the same LINQ for when I get the properties using reflection to sort the passed list.
Other than the slightly complex code, what I like about my solution is that it's clear to see how it operates and can be very flexible. Perhaps only thing is the switch statement should be ordered in reverse order so it's slightly easier to understand.