Baishampayan Ghose
Baishampayan Ghose

Reputation: 20696

How can I calculate the age of a person in year, month, days?

I want to calculate the age of a person given the date of birth and the current date in years, months and days relative to the current date.

For example:

>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days

Any pointer to an algorithm that does that will be appreciated.

Upvotes: 18

Views: 66333

Answers (13)

Johan
Johan

Reputation: 257

Thanks Marcus, your code works well. Here is my version in Delphi Language >>

Const
  YMD :  array[1..12] of byte = (31,28,31,30,31,30,31,31,30,31,30,31);
  LYMD : array[1..12] of byte = (31,29,31,30,31,30,31,31,30,31,30,31);

function GetMaxMonthDays(aDate : TDateTime): Word;
var
  Year, Month, Day : Word;
begin
  DecodeDate(aDate, Year, Month, Day);
  if IsLeapYear(Year) then
    result := LYMD[Month]
  else
    result := YMD[Month];
end;

procedure DeltaDates(Date1, Date2: TDateTime; var years, months, days: integer);
var
  Year1, Month1, Day1, Year2, Month2, Day2 : Word;
begin
  DecodeDate(Date1, Year1, Month1, Day1);
  DecodeDate(Date2, Year2, Month2, Day2);
  years := Year2 - Year1;
  months :=  Month2 - Month1;
  days := Day2 - Day1;
  if days < 0 then
  begin
    dec(months);
    days := days + GetMaxMonthDays(IncMonth(Date2,-1));
  end;
  if months < 0 then
  begin
    dec(years);
    months := months + 12;
  end;
end;

Upvotes: 0

Anupam Hayat Shawon
Anupam Hayat Shawon

Reputation: 153

You can use PHP date_diff http://php.net/manual/en/function.date-diff.php or http://www.php.net/manual/en/datetime.diff.php to achieve what you want and you can output it in any format you want using PHP date format

$interval = date_diff(date_create(), date_create('2008-01-01 10:30:00')); echo $interval->format("You are %Y Year, %M Months, %d Days, %H Hours, %i Minutes, %s Seconds Old");

Result: You are 04 Year, 04 Months, 1 Days, 00 Hours, 56 Minutes, 36 Seconds Old

Upvotes: 0

Capriatto
Capriatto

Reputation: 965

This Algorithm prints the next format -> 24 Years, 8 Months,2 Days

from dateutil.relativedelta import *
from datetime import date

def calc_age(dob):
  today = date.today()
  age = relativedelta(today, dob)
  print str(age.years)+" Years, "+str(age.months)+" Months,"+str(age.days)+" Days"

#test it
calc_age(date(1993,10,10))

Upvotes: 0

informaticienzero
informaticienzero

Reputation: 1867

I know it's a bit outdated, but here is a simple code that I used,with the power of the Python library (Python 3.5 for annotations, but works without).

from datetime import date, timedelta

def age(birth: date) -> (int, int, int):
        """
            Get a 3-int tuple telling the exact age based on birth date.
        """
        today_age = date(1, 1, 1) + (date.today() - birth)
        # -1 because we start from year 1 and not 0.
        return (today_age.year - 1, today_age.month - 1, today_age.day - 1)

Upvotes: 0

I assume the questions is broader than only one programming language. If you are using C#, you can use DateTimeOffset to calculate this.

var offset = DateTimeOffset.MinValue;
var lastDate = DateTime.Today;
var firstDate = new DateTime(2006,11,19);


var diff = (lastDate- firstDate);
var resultWithOffset = DateTimeOffset.MinValue.AddDays(diff.TotalDays);
var result = resultWithOffset.AddDays(-offset.Day).AddMonths(-offset.Month).AddYears(-offset.Year);

result.Day, result.Month, result.Year will hold the information you need.

Upvotes: 0

wye
wye

Reputation: 356

The Swift implementation of dreeves' answer.

ps. instead of (y,m,d) (ynow,mnow,dnow) as the inputs, I use two NSDate's, which may be more handy in real world usages.

extension NSDate {

    convenience init(ageDateString:String) {
        let dateStringFormatter = NSDateFormatter()
        dateStringFormatter.dateFormat = "yyyy-MM-dd"
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        let d = dateStringFormatter.dateFromString(ageDateString)!
        self.init(timeInterval:0, sinceDate:d)
    }

    func ageFrom(date: NSDate) -> (Int, Int, Int) {
        let cal = NSCalendar.currentCalendar()

        let y = cal.component(NSCalendarUnit.Year, fromDate: date)
        let m = cal.component(NSCalendarUnit.Month, fromDate: date)
        let d = cal.component(NSCalendarUnit.Day, fromDate: date)
        let ynow = cal.component(NSCalendarUnit.Year, fromDate: self)
        let mnow = cal.component(NSCalendarUnit.Month, fromDate: self)
        let dnow = cal.component(NSCalendarUnit.Day, fromDate: self)

        let t0 = y * 12 + m - 1       // total months for birthdate.
        var t = ynow * 12 + mnow - 1;   // total months for Now.
        var dm = t - t0;              // delta months.
        if(dnow >= d) {
            return (Int(floor(Double(dm)/12)), dm % 12, dnow - d)
        }
        dm--
        t--
        return (Int(floor(Double(dm)/12)), dm % 12, Int((self.timeIntervalSince1970 - NSDate(ageDateString: "\(Int(floor(Double(t)/12)))-\(t%12 + 1)-\(d)").timeIntervalSince1970)/60/60/24))
    }

}

// sample usage
let birthday = NSDate(ageDateString: "2012-7-8")
print(NSDate().ageFrom(birthday))

Upvotes: 0

Rajeshwaran S P
Rajeshwaran S P

Reputation: 582

Here is this using the borrowing rule of mathematics.

        DateTime dateOfBirth = new DateTime(2000, 4, 18);
        DateTime currentDate = DateTime.Now;

        int ageInYears = 0;
        int ageInMonths = 0;
        int ageInDays = 0;

        ageInDays = currentDate.Day - dateOfBirth.Day;
        ageInMonths = currentDate.Month - dateOfBirth.Month;
        ageInYears = currentDate.Year - dateOfBirth.Year;

        if (ageInDays < 0)
        {
            ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
            ageInMonths = ageInMonths--;

            if (ageInMonths < 0)
            {
                ageInMonths += 12;
                ageInYears--;
            }
        }
        if (ageInMonths < 0)
        {
            ageInMonths += 12;
            ageInYears--;
        }

        Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays);

Upvotes: 0

dreeves
dreeves

Reputation: 26962

First, note the assumption that if, for example, you were born on February 1st then on the following March 1st, you are exactly 1 month old, even though your age in days is only 28 -- less than the length of an average month. Years also have variable length (due to leap years) which means your age on your birthday is usually not an exact integer number of years. If you want to express the exact amount of time you've been alive in years/months/days, see my other answer. But more likely you want to fudge it just right so that being born on February 1st means that every February 1st you are X years, 0 months, and 0 days old, and on the 1st of any month you are X years, Y months, and 0 days.

In that case, read on. (NB: the following only works for dates in the past.)

Given a date of birth, (y,m,d), the current date, (ynow,mnow,dnow), and a function tm() that gives unix/epoch time for a given date, the following will output a 3-element list giving age as {years, months, days}:

t0 = y*12 + m - 1;        # total months for birthdate.
t = ynow*12 + mnow - 1;   # total months for Now.
dm = t - t0;              # delta months.    
if(dnow >= d) return [floor(dm/12), mod(dm,12), dnow-d];
dm--; t--;
return [floor(dm/12), mod(dm,12), 
        (tm({ynow,mnow,dnow}) - tm({floor(t/12), mod(t,12)+1, d}))/60/60/24];

Following is an equivalent algorithm if you don't like all the floors and mods. But I think the above is better. For one thing it avoids calling tm() when it doesn't need to.

{yl, ml} = {ynow, mnow};
if(mnow < m || mnow == m && dnow < d) yl--;
if(dnow < d) ml--;
years = yl - y;
months = ml + 12*(ynow - yl) - m;
yl = ynow;
if(ml == 0) { ml = 12; yl--; }
days = (tm({ynow, mnow, dnow}) - tm({yl, ml, d}))/60/60/24;
return [years, months, days];

Upvotes: 17

Fernando Migu&#233;lez
Fernando Migu&#233;lez

Reputation: 11326

That is not an easy question, since above days (if we don't take into account leap-seconds) there are not easy formulas.

Months can consist of 28, 29, 30, or 31 days; years can be 365 or 366 days. Therefore, problems arise when you try to calculate full units of time for months and years.

Here is an interesting article that takes into account all the complex aspects to solve your question in Java.

Upvotes: 4

Shannon Nelson
Shannon Nelson

Reputation: 2126

Others here have the right idea - you simply need be able to extend it to other languages. Many computer systems count time in seconds from a specific point (the "epoch" or "reference date") and figure out the date from there, as well as offering methods to convert from seconds to dates. You should be able to get the current time in seconds, convert the birth date to seconds from the epoch, subtract the two values, then divide that by the number of seconds in a day:

int timenow = time(0);
struct tm birthday = { tm_mday = 16 , .tm_mon = 1 , .tm_year = 1963 };
int timebirth = mktime( &birthday_tm );
int diff_sec = timenow - timebirth;
int days = diff_sec / ( 24 * 60 * 60);
printf("%d - %d = %d seconds, or %d days\n", timenow, timebirth, diff_sec, days);

The bug in this particular code is that mktime() can't deal with dates before the epoch, which is Jan 1 1970 in Unix based systems. Similar issues will exist on other systems depending on how they count time. The general algorithm should work, you just have to know your limits on specific systems.

Upvotes: 3

Marcus Downing
Marcus Downing

Reputation: 10141

Since years, months and even days can have uneven lengths, you can't start by subtracting the two dates to get a simple duration. If you want the result to match up with how human beings treat dates, you instead have to work with real dates, using your language's built in functions that understand dates better than you ever will.

How that algorithm is written depends on the language you use, because each language has a different set of functions. My own implementation in Java, using the awkward but technically correct GregorianCalendar:

Term difference (Date from, Date to) {
    GregorianCalendar cal1 = new GregorianCalendar();
    cal1.setTimeInMillis(from.getTime());

    GregorianCalendar cal2 = new GregorianCalendar();
    cal2.setTimeInMillis(to.getTime());

    int years = cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR);
    int months = cal2.get(Calendar.MONTH) - cal1.get(Calendar.MONTH);
    int days = cal2.get(Calendar.DAY_OF_MONTH) - cal1.get(Calendar.DAY_OF_MONTH);
    if (days < 0) {
        months--;
        days += cal1.getActualMaximum(Calendar.DAY_OF_MONTH);
    }
    if (months < 0) {
        years--;
        months += 12;
    }
    return new Term(years, months, days);
}

This may not be perfect, but it delivers human-readable results. Term is a class of my own for storing human-style periods, since Java's date libraries don't have one.

For future projects I plan to move to the much better Joda date/time library, which does have a Period class in it, and will probably have to rewrite this function.

Upvotes: 2

dreeves
dreeves

Reputation: 26962

Here's a way to do it if you're willing to violate the principle of "I should be an integer number of years old on my birthday". Note that that principle isn't strictly true, due to leap years, so the following is actually more accurate, though perhaps less intuitive. If you want to know the actual exact number of years old someone is, this is the way I would do it.

First convert both the birthdate and the current time to epoch time (number of seconds since the dawn of time, ie, 1970 in unix land) and subtract them. See, eg, this question for how to do that: How do I convert a date/time to epoch time (aka unix time -- seconds since 1970) in Perl?. You now have the person's exact age in seconds and need to convert that to a string like "36 years, 3 months, 8 days".

Here's pseudocode to do it. It should be straightforward to remove the weeks or hours or whatever parts you don't want...

daysInYear = 365.2425;  # Average lengh of a year in the gregorian calendar.
                        # Another candidate for len of a year is a sidereal year,
                        # 365.2564 days.  cf. http://en.wikipedia.org/wiki/Year
weeksInYear = daysInYear / 7;
daysInMonth = daysInYear / 12;
weeksInMonth = daysInMonth / 7;
sS = 1;
mS = 60*sS;
hS = 60*mS;
dS = 24*hS;
wS = 7*dS;
oS = daysInMonth*dS;
yS = daysInYear*dS;

# Convert a number of seconds to years,months,weeks,days,hrs,mins,secs.
seconds2str[secs] 
{
  local variables:
    y, yQ= False, o, oQ= False, w, wQ= False,
    d, dQ= False, h, hQ= False, m, mQ= False, s= secs;

  if(secs<0) return "-" + seconds2str(-secs);  # "+" is string concatenation.

  y = floor(s/yS);
  if(y>0) yQ = oQ = wQ = dQ = hQ = mQ = True;
  s -= y * yS;

  o = floor(s/oS);
  if(o>0) oQ = wQ = dQ = hQ = mQ = True;
  s -= o * oS;

  w = floor(s/wS);
  if(w>0) wQ = dQ = hQ = mQ = True;
  s -= w * wS;

  d = floor(s/dS);
  if(d>0) dQ = hQ = mQ = True;
  s -= d * dS;

  h = floor(s/hS);
  if(h>0) hQ = mQ = True;
  s -= h * hS;

  m = floor(s/mS);
  if(m>0) mQ = True;
  s -= m * mS;

  return
    (yQ ? y + " year"  + maybeS(y) + " " : "") + 
    (oQ ? o + " month" + maybeS(o) + " " : "") + 
    (wQ ? w + " week"  + maybeS(w) + " " : "") + 
    (dQ ? d + " day"   + maybeS(d) + " " : "") + 
    (hQ ? dd(h) + ":" : "") + 
    (mQ ? dd(m) + ":" + dd(round(s)) + "s" : s + "s");
}


# Returns an "s" if n!=1 and "" otherwise.
maybeS(n) { return (n==1 ? "" : "s"); }

# Double-digit: takes a number from 0-99 and returns it as a 2-character string.
dd(n) { return (n<10 ? "0" + tostring(n) : tostring(n)); }

Upvotes: 2

Martin Thurau
Martin Thurau

Reputation: 7654

Since you are obviously using python: Create to datetime objects, one with "birthday" and one with "now", subtract them and read the age from the resulting timedelta object.

Why bothering with things like leap years?

Upvotes: -4

Related Questions