Here is a response关于计算Java年龄的question。
/**
* 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)
到目前为止,我已经创建了一个巨大的电子表格,记录了一年中的所有差异,试图查看它可能涵盖的案例,但我没有看到其他比较没有涵盖的任何内容。任何人都能解释包含这种比较背后的目的吗?它在某种程度上更有效吗?
答案 0 :(得分: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)海报希望“改善”表现以下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的作用相对应。也许年度检查来自一些早期的基于日期的建议代码版本,并且还没有被清理过。
为了回答你的上一个问题:这样的不必要的检查不是很好。在性能方面有效(尽管我们在这里谈论微观优化)。