Java的Calendar.DAY_OF_YEAR有时会偏移一个。

5

我正在尝试根据用户的出生日期获取其年龄。出生日期以 XML 字符串的形式给出,并转换为 Calendar,如下所示:

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

然后我按照以下方式计算用户的年龄:

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;
}

我今天发现,如果今天是用户的生日(别拿出派对帽子,这不是我的生日),年龄会少算一岁。也就是说,如果用户出生于2000年,而今天是她的生日,她应该是14岁,而不是13岁。但归根结底,Java似乎计算DAY_OF_YEAR有误:

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

怎么回事?


考虑在Java 8中使用新的java.time包进行日期计算。 - Mark Rotteveel
2个回答

8
一个边缘情况引起了问题。
2000年有什么特别之处?
它是一个闰年。
    Calendar cal = new GregorianCalendar();
    cal.set(2000, 11, 31);
    System.out.println(cal.getTime());
    System.out.println(cal.get(Calendar.DAY_OF_YEAR));

输出:

2000年12月31日星期日 13:43:28 美国东部时间
366

在闰年后2月29日之后的所有日期都会偏移1天,这是正确的。实际上,它正按照预期工作。

您应该比较月份和日期来解决此问题。


谢谢你的回答。你赢得了我见过的最多编辑奖,仅仅在几分钟内就完成了。请给我测试解决方案的机会! - meustrus
这也不是竞争条件。我想你可以称之为边缘情况。但是,感谢您发现了闰年问题。 - meustrus
@meustrus,我已经为您进行了编辑,将其更改为“边缘”。 - Compass

0

使用joda:

DateTime jodaDob = new DateTime(dob);
DateTime now = new DateTime();
if (jodaDob.isAfter(now)) {
    age = age - 1;
}

java.util.Date在一些边界情况下存在很多bug,而joda库对此进行了处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接