chinabugotech/hutool · error · IllegalArgumentException

Birthday is after dateToCompare!

Error message

Birthday is after dateToCompare!

What it means

Thrown by CalendarUtil.age(long birthday, long dateToCompare) when the birthday timestamp is greater than the comparison date timestamp — i.e., the birthday is in the future relative to the date being compared. This is a logic error: you cannot compute age when the birth date is after the reference date. The method implements Chinese legal age reckoning (周岁).

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java:708

		return result.toString();
	}

	/**
	 * 计算相对于dateToCompare的年龄,常用于计算指定生日在某年的年龄<br>
	 * 按照《最高人民法院关于审理未成年人刑事案件具体应用法律若干问题的解释》第二条规定刑法第十七条规定的“周岁”,按照公历的年、月、日计算,从周岁生日的第二天起算。
	 * <ul>
	 *     <li>2022-03-01出生,则相对2023-03-01,周岁为0,相对于2023-03-02才是1岁。</li>
	 *     <li>1999-02-28出生,则相对2000-02-29,周岁为1</li>
	 * </ul>
	 *
	 * @param birthday      生日
	 * @param dateToCompare 需要对比的日期
	 * @return 年龄
	 */
	protected static int age(long birthday, long dateToCompare) {
		if (birthday > dateToCompare) {
			throw new IllegalArgumentException("Birthday is after dateToCompare!");
		}

		final Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(dateToCompare);

		final int year = cal.get(Calendar.YEAR);
		final int month = cal.get(Calendar.MONTH);
		final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);

		// 复用cal
		cal.setTimeInMillis(birthday);
		int age = year - cal.get(Calendar.YEAR);

		//当前日期,则为0岁
		if (age == 0) {
			return 0;
		}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Validate that birthday <= dateToCompare before calling age(): if (birthday <= dateToCompare) { age(birthday, dateToCompare); }.
  2. Check argument order: the first parameter is birthday (earlier), the second is dateToCompare (later).
  3. Validate user-supplied birth dates to ensure they are not in the future: if (birthDate.after(new Date())) reject.
  4. Use DateUtil.age(Date, Date) overload which delegates here, and pre-validate both Date arguments.

Example fix

// before
int age = DateUtil.age(birthdayDate, compareDate); // throws if birthday is future

// after
if (!birthdayDate.after(compareDate)) {
    int age = DateUtil.age(birthdayDate, compareDate);
} else {
    // handle invalid birth date
}
Defensive patterns

Strategy: validation

Validate before calling

if (birthday > dateToCompare) {
    throw new IllegalArgumentException("Birthday cannot be after the comparison date");
}
// or skip:
if (birthday <= dateToCompare) {
    int age = DateUtil.age(birthday, dateToCompare);
}

Type guard

static boolean isValidAgeInput(long birthday, long dateToCompare) {
    return birthday <= dateToCompare;
}

Try / catch

try {
    return DateUtil.age(birthdayDate, compareDate);
} catch (IllegalArgumentException e) {
    // birthday is in the future relative to compare date
    return 0; // or handle per business rule
}

Prevention

When it happens

Trigger: Calling DateUtil.age(futureBirthdayMillis, nowMillis) where the birthday epoch millis are after dateToCompare. Swapping argument order: passing the comparison date as 'birthday' and the birthday as 'dateToCompare'. System clock rollback or data entry putting a future birth date.

Common situations: User form where birth date is accidentally set to a future date. Data import with swapped date columns (e.g., 'created_date' passed as birthday). Test data with incorrect epoch values. System clock issues in environments causing dateToCompare to be earlier than expected.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/fa144f2a12c0f5b5. Report an issue: GitHub.