aroth
aroth

Reputation: 54806

Java: Basic Math Error?

I must be doing something fundamentally wrong here. I've got very simple code:

private static final long MILLIS_PER_YEAR = 1000 * 60 * 60 * 24 * 365;

//...

public long getAge() {
    long millis = System.currentTimeMillis() - this.getBirthdate().getTime();
    System.out.println("Computed age:  " + (millis / MILLIS_PER_YEAR) + ", birthdate=" + this.getBirthdate() + ", birthdateMillis=" 
            + this.getBirthdate().getTime() + ", now=" + new Date() + ", nowMillis=" + System.currentTimeMillis() 
            + ", elapsedMillis=" + millis);
    return millis / MILLIS_PER_YEAR;
}

...but it's giving some completely incorrect output:

Computed age:  248, birthdate=2001-01-01 10:00:00.0, birthdateMillis=978307200000, now=Fri Aug 10 16:56:48 EST 2012, nowMillis=1344581808173, elapsedMillis=366274608173
Computed age:  184, birthdate=2004-01-01 10:00:00.0, birthdateMillis=1072915200000, now=Fri Aug 10 16:56:48 EST 2012, nowMillis=1344581808173, elapsedMillis=271666608173

If I run the same computation manually (or by using Google), I get the correct result (within a reasonable allowance, due to the fact that there are slightly more than 365 days in a real year).

How is it that the same math is producing such nonsensical output in this code?

Upvotes: 3

Views: 243

Answers (1)

Joachim Sauer
Joachim Sauer

Reputation: 308031

The value of MILLIS_PER_YEAR is wrong. It's 1471228928 instead of the desired 31536000000.

Look at the calculation of the value: all participating values are int values (numeric, non-decimal constants are int-values by default in Java). This means that the result of the calculation will be an int value as well. But the desired value is bigger than an int can hold, so you'll have an overflow.

To ensure that the caluclation is done on long values, simply make at least one of the values a long (by appending the L suffix):

private static final long MILLIS_PER_YEAR = 1000L * 60 * 60 * 24 * 365;

Upvotes: 13

Related Questions