为什么这个 Java 代码有这个年龄验证日期比较?

Why does this Java code have this age validation date comparison?

Here is a response to a question关于在Java.

计算年龄
/**
 * This Method is unit tested properly for very different cases , 
 * taking care of Leap Year days difference in a year, 
 * and date cases month and Year boundary cases (12/31/1980, 01/01/1980 etc)
**/

public static int getAge(Date dateOfBirth) {

    Calendar today = Calendar.getInstance();
    Calendar birthDate = Calendar.getInstance();

    int age = 0;

    birthDate.setTime(dateOfBirth);
    if (birthDate.after(today)) {
        throw new IllegalArgumentException("Can't be born in the future");
    }

    age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR);

    // If birth date is greater than todays date (after 2 days adjustment of leap year) then decrement age one year   
    if ( (birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3) ||
            (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH ))){
        age--;

     // If birth date and todays date are of same month and birth day of month is greater than todays day of month then decrement age
    }else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) &&
              (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){
        age--;
    }

    return age;
}

这段代码工作正常,但为什么会有这样的比较: (birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3)

我什至创建了一个包含一年中所有日期差异的巨大电子表格,以尝试查看它可能涵盖的情况,但我没有看到其他比较没有发现的任何内容覆盖。任何人都可以解释包括这种比较背后的目的吗?它在某些方面更有效吗?

来自 ThreetenBP 的以下代码示例(Java-8 的向后移植)支持 不需要年度检查 的声明:

@Override 
public long until(Temporal endExclusive, TemporalUnit unit) { 
LocalDate end = LocalDate.from(endExclusive); 
    if (unit instanceof ChronoUnit) { 
         switch ((ChronoUnit) unit) { 
             case DAYS: return daysUntil(end); 
             case WEEKS: return daysUntil(end) / 7; 
             case MONTHS: return monthsUntil(end); 
             case YEARS: return monthsUntil(end) / 12; 
             case DECADES: return monthsUntil(end) / 120; 
             case CENTURIES: return monthsUntil(end) / 1200; 
             case MILLENNIA: return monthsUntil(end) / 12000; 
             case ERAS: return end.getLong(ERA) - getLong(ERA); 
         } 
         throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); 
     } 
     return unit.between(this, end); 
} 

[...]     

private long monthsUntil(LocalDate end) { 
   long packed1 = getProlepticMonth() * 32L + getDayOfMonth();  // no overflow 
   long packed2 = end.getProlepticMonth() * 32L + end.getDayOfMonth();  // no overflow 
   return (packed2 - packed1) / 32; 
} 

case YEARS: return monthsUntil(end) / 12;(表达式 birthday.until(today, YEARS)YEARS.between(birthday, today) 是等效的 - 一个委托给另一个)利用与 OP 引用的以下简化代码相同的算法并且不引用到一年中的任何一天检查:

age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR);

if (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH)) {
    age--;
}else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) &&
          (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){
    age--;
}

问题来了:为什么要检查年份?

a) 发帖人最初认真对待年的一天的想法,然后忘记在以后的版本中清理

b) 发帖者希望"improve"表现

下面的Java-8代码演示了如果认真对待并作为完整版本的基于年的算法的问题(库的选择在这里不相关,只有算法很重要):

LocalDate birthday = LocalDate.of(2001, 3, 6);
LocalDate today = LocalDate.of(2016, 3, 5); // leap year

int age = today.getYear() - birthday.getYear();
if (birthday.getDayOfYear() > today.getDayOfYear()) {
    age--;
}
System.out.println("age based on day-of-year: " + age); // 15 (wrong)
System.out.println("age based on month and day-of-month: " 
  + ChronoUnit.YEARS.between(birthday, today)); // 14 (correct)

结论:

您引用的提议的年度条款只是噪音,因为算法的其余部分对应于 Java-8 所做的。也许年度检查源自一些较早的基于年度的建议代码版本并且尚未清理。

为了回答你的最后一个问题:像这样不必要的检查是不好的。在性能方面高效(尽管我们在这里谈论微优化)。