user_01 user_01 - 2 months ago 42
Java Question

Calculate age in java considering leap years

I would like to calculate exact age in days considering leap years. I researched on the web, found some tutorials, but with leap years that exactly calculates difference of dates in days seems to be the one in [1]: https://answers.yahoo.com/question/index?qid=20110629162003AAof4mT this link, which is "best answer" . I analyzed code but have two questions:

1) Why it writes "days = days + leapYears" below "Calculate days lives" section and

2) Finally, how can I input birthday date with day,month and year and current day,month,year and find difference of these two dates in days within this code in the main method? I really appreciate your help. Thanks in advance !

PS: For convenience, I have included the code from the link I showed above:

public class Days {


static int leapYear(int year) {
int leap;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
leap = 1;
}
else {
leap = 0;
}
return leap;
}

static int daysBefore(int month, int day, int year){
int days = 0;
int monthDays[] = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (leapYear(year) == 1){
monthDays[1] = 29;
}
for (int b = 0; b < month - 1; b++){
days = days + monthDays[b];
}
days = days + day;
return days;
}
public static void main(String[] args) {
//Birth date
int birthMonth = 0;
int birthDay = 0;
int birthYear = 0;

//Due date
int dueMonth = 0;
int dueDay = 0;
int dueYear = 0;

//(1) Calculate years lived
int yearsLived = dueYear - birthYear + 1;

//(2) Calculate leap years
int leapYears = 0;
for (int year = birthYear; year < dueYear+1; year++)
{
leapYears = leapYears + leapYear(year);
}

//(3) Calculate the number of days in your birth year before birth
int daysBeforeBirth = daysBefore(birthMonth, birthDay, birthYear);

//(4) Calculate the number of days remaining in the current year after the due date
int daysRemaining = 365 - daysBefore(dueMonth, dueDay, dueYear);

//Calculate days lived
int days = 0;
days = days + (365 * yearsLived);
days = days + leapYears;
days = days - daysBeforeBirth;
days = days - daysRemaining;
}
}

Answer

The correct way to do this is with the Period and LocalDate classes in the java.time package. However, it seems that you're trying to reinvent the calculation for yourself.

The way that I would recommend doing this is to write a class that lets you calculate a "day number" for a given date - that is, the number of days between the specified date, and some arbitrary date in the past. Then when you want to find the number of days between two specified dates, you can just use calculate the "day number" for both dates, and subtract them.

I have done that here, for a purely Gregorian calendar. This class is no good before the Gregorian cutover - I haven't tried to build a historically accurate Julian/Gregorian hybrid calendar, such as the JDK provides. And the arbitrary date in the past that it calculates day numbers from is 31 December, 2BC. This date, of course, isn't really part of the Gregorian calendar; but for our purposes here, it doesn't matter.

Since you're unlikely to encounter any dates before the Gregorian cutover, this class should be more than adequate for your purposes. I still recommend using the Period and LocalDate classes instead of this one, for production code. This is just here so you can see how to do the calculations.

public class GregorianDate {

    private final int day;
    private final int month;
    private final int year;

    private static final int[] DAYS_PER_MONTH = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    public GregorianDate(int day, int month, int year) {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    public boolean isValid() {
        return month >= 1 && month <= 12 && day >= 1 && day <= daysThisMonth();
    }

    public static int daysBetween(GregorianDate from, GregorianDate to) {
        return to.dayNumber() - from.dayNumber();
    }

    public static int daysBetween(int fromDay, int fromMonth, int fromYear, int toDay, int toMonth, int toYear) {
        return daysBetween(new GregorianDate(fromDay, fromMonth, fromYear), new GregorianDate(toDay, toMonth, toYear));
    }

    private int daysThisMonth() {
        return (isLeapYear() && month == 2) ? 29 : DAYS_PER_MONTH[month];
    }

    private int dayNumber() {
        return year * 365 + leapYearsBefore() + daysInMonthsBefore() + day;
    }

    private boolean isLeapYear() {
        return ( year % 4 == 0 &&  year % 100 != 0 ) || year % 400 == 0;  
    }

    private int leapYearsBefore() {
        return year / 4 - year / 100 + year / 400;
    }

    private int daysInMonthsBefore() {
        switch(month) {
        case 1: 
            return 0;
        case 2:
            return 31;
        default:
            // Start with the number in January and February combined
            int toReturn = isLeapYear() ? 60 : 59; 
            for (int monthToConsider = 3; monthToConsider < month; monthToConsider++) {
                toReturn += DAYS_PER_MONTH[monthToConsider];
            }
            return toReturn;
        }
    }

}