5

I am a newbie and appreciate if someone help me out.

When I tried to calculate age using the below source , it does not give me the value of what I want . For example : date->29/12/2010 , dob->30/12/1992 , it will give me 18 instead of 17. Is there any method that I can code to return me 17yrs 11mths based on the above 2 dates instead of 18yrs0mths?

public double getAgeAsOf( Date date ) {
        return ((date.getTime() - dob.getTime())/(1000*60*60*24))/365;
    }

Thanks.

blueberry
  • 51
  • 1
  • 1
  • 2

2 Answers2

18

You can use Joda Time and compute a Period between two LocalDate values (which is what you've got here) using months and years as the units.

Sample code:

import org.joda.time.*;

public class Test {
    public static void main(String[] args) {
        LocalDate dob = new LocalDate(1992, 12, 30);
        LocalDate date = new LocalDate(2010, 12, 29);

        Period period = new Period(dob, date, PeriodType.yearMonthDay());
        System.out.println(period.getYears() + " years and " +
                           period.getMonths() + " months");
    }
}

(This uses a period type which includes days as well, but that won't affect the answer.)

In general, Joda Time is a much better API than using Date/Calendar - and you really don't want to get into the business of performing date calculations yourself if you can avoid it. It gets messy really quickly.

As per aioobe's answer, if you divide two integer expressions the arithmetic will be performed in integer arithmetic, which may not be what you want - but for date and time arithmetic, just let someone else do the hard work in the first place :)

The code above will use the ISO-8601 calendar by the way, which is basically the Gregorian calendar. If you want to use something else, specify it as another constructor argument after the year/month/day for LocalDate.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
2

You have a few problems with your code:

  1. You're doing integer division, which truncates the result to the closest lower integer.

    For example, if you divide 729 by 365 you'll get 1 (and you've lost the fractional part, which you would need when calculating months etc)

  2. Another problem is that you're using 365 days for one year, while it is actually closer to 365.25 (when including extra days due to leap years).

Here's a slightly improved snippet of code:

import java.util.Date;

public class Test {
    
    static double msPerGregorianYear = 365.25 * 86400 * 1000;
    
    static Date dob = new Date(1992, 12, 30);
    
    public static double getAgeAsOf(Date date) {
        return (date.getTime() - dob.getTime()) / msPerGregorianYear;
    }

    public static void main(String[] args) {
        
        double years = getAgeAsOf(new Date(2010, 12, 29));
        
        // years == 17.99315537303217

        int yy = (int) years;
        int mm = (int) ((years - yy) * 12);
        
        // Prints   "17 years and 11 moths."
        System.out.printf("%d years and %d moths.", yy, mm);
    }
}

If you're ever doing anything more complicated than figuring out the number of years given the number of milliseconds, I suggest you turn to some time-library such as Joda time as suggested by Jon Skeet.

Community
  • 1
  • 1
aioobe
  • 383,660
  • 99
  • 774
  • 796
  • 17 + 364/365 rounds down to 17. The issue is leap years, as pointed out by Paulo's comment. – Wooble Mar 21 '11 at 14:26
  • That still assumes *exactly* 365 days in a year. It won't always be correct. Basically, date calculation is best done with an API rather than performing simple arithmetic like this. – Jon Skeet Mar 21 '11 at 14:27
  • Right. Answer updated. Generally I agree. But for simple tasks like this, and for beginner questions it is more instructive to explain what went wrong and how to correct it. By just suggesting a jar-file that solves his particular problem, the OP will be back with another integer-division problem in a month or so. – aioobe Mar 21 '11 at 14:32
  • @aioobe: True - but hopefully *not* for a date/time question where they shouldn't be doing arithmetic in the first place. And I don't think it's actually that simple a task anyway. Even the "average millis per year" isn't constant over a 4 year period, as leap years don't occur *every* four years. Your code would probably fail around 2098-2102, for example. The fact that it would work around 2000 is only a coincidence because 2000 was a leap year as it's divisible by 400 as well as 100. – Jon Skeet Mar 21 '11 at 14:37
  • Right. For your last point, it depends on the definition of a year. If it's someones *age* we're talking about, I bet we're using the definition of a Julian year, which is exactly 31557600 seconds long. – aioobe Mar 21 '11 at 14:40
  • @aioobe: I think it's more likely we're using a Gregorian year, as the Gregorian calendar is more commonly used than the Julian one. (For example, the ISO-8601 calendar is based on the Gregorian calendar.) – Jon Skeet Mar 21 '11 at 14:41
  • @Jon, ah, right. Got it mixed up. Luckily though, Gregorian have just as long years as the Julian calendar if I understand it correctly. – aioobe Mar 21 '11 at 14:48