Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Calendar.DAY_OF_YEAR sometimes off by one

Tags:

java

javax.xml

I am trying to get a user's age based on their date of birth. The date of birth is given as a string in XML and converted to a Calendar like so:

final Calendar dob = javax.xml.bind.DatatypeConverter.parseDate(value);

Then I am calculating the user's age like so:

final Calendar now = Calendar.getInstance();
int age = now.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
if (now.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) {
  --age;
}

I discovered today that if today is the user's birthday (put the party hats away, it isn't mine), the age comes out a year too young. That is, if the user was born in 2000 and today is her birthday, she should be 14 years old, not 13. But when it comes down to it, Java seems to have the DAY_OF_YEAR wrong:

System.out.println(String.format("Today: %d-%d; Birthday: %d-%d", now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH), dob.get(Calendar.MONTH), dob.get(Calendar.DAY_OF_MONTH)));
// prints: Today: 9-22; Birthday: 9-22
System.out.println(String.format("Today: %d; Birthday: %d", now.get(Calendar.DAY_OF_YEAR), dob.get(Calendar.DAY_OF_YEAR)));
// prints: Today: 295; Birthday: 296

What gives?

like image 383
meustrus Avatar asked Oct 22 '14 17:10

meustrus


1 Answers

An edge condition is causing the issue.

What is special about 2000?

It's a leap year.

    Calendar cal = new GregorianCalendar();
    cal.set(2000, 11, 31);
    System.out.println(cal.getTime());
    System.out.println(cal.get(Calendar.DAY_OF_YEAR));

Output:

Sun Dec 31 13:43:28 EST 2000
366

Everything after February 29th is offset by 1 specifically for leap years. Ergo, it's not wrong. In fact, it's working as intended.

You should instead be comparing month and day of month to get around this issue.

like image 68
Compass Avatar answered Sep 28 '22 16:09

Compass