Age calculator in Java projects are a practical way to learn Java’s modern date and time API while solving a familiar problem: converting a date of birth into a person’s completed age. The key is to calculate age by calendar birthdays rather than simply subtracting years or dividing elapsed days by 365.
This guide shows how to calculate completed age, age on a fixed cutoff date, exact years-months-days, elapsed days, validated DOB input, leap-year cases, and reusable Java methods. It uses java.time.LocalDate and java.time.Period, the standard date API for date-only calculations. For related implementations, see our age calculator in Python, age calculator in PHP, age calculator in Excel, and age calculator in Google Sheets guides.

Quick answer: calculate completed age in Java
For a normal birthday-based age, use LocalDate and compare the birthday with the reference date. Java’s year difference alone is not enough because a person who has not reached their birthday yet has not completed another year.
import java.time.LocalDate;
public class AgeCalculator {
public static int calculateAge(LocalDate birthDate, LocalDate today) {
if (birthDate.isAfter(today)) {
throw new IllegalArgumentException(
"Birth date cannot be in the future."
);
}
int age = today.getYear() - birthDate.getYear();
if (today.getMonthValue() < birthDate.getMonthValue()
|| (today.getMonthValue() == birthDate.getMonthValue()
&& today.getDayOfMonth() < birthDate.getDayOfMonth())) {
age--;
}
return age;
}
public static void main(String[] args) {
LocalDate dob = LocalDate.of(1995, 8, 21);
System.out.println(calculateAge(dob, LocalDate.now()));
}
}
Java’s LocalDate represents a date without a time zone, which fits a date of birth or birthday-based age calculation. Oracle’s current Java documentation also provides until() and Period.between() for calculating calendar differences. Java LocalDate documentation.
Why subtracting years alone gives wrong ages
A first attempt such as today.getYear() - birthDate.getYear() works only after the birthday has occurred in the reference year. Before the birthday, one year must be removed.
| Birth date | Reference date | Completed age | Reason |
|---|---|---|---|
| 21 Aug 1995 | 20 Aug 2026 | 30 | Birthday is tomorrow |
| 21 Aug 1995 | 21 Aug 2026 | 31 | Birthday is today |
| 21 Aug 1995 | 22 Aug 2026 | 31 | Birthday has passed |
Use LocalDate for a date of birth
LocalDate is a natural fit when the input is a calendar date such as 2000-05-10. It stores year, month, and day without a time-of-day or time-zone component. That keeps ordinary age calculations separate from timestamp and time-zone problems.
LocalDate dob = LocalDate.of(2000, 5, 10);
LocalDate today = LocalDate.now();
System.out.println("DOB: " + dob);
System.out.println("Today: " + today);
The LocalDate API also supports comparisons such as isBefore(), isAfter(), and isEqual(). For an age calculator, these methods make validation and boundary checks readable.
Calculate age on a specific date
Many eligibility questions use a stated cutoff date instead of today’s date. The safest design is to pass that reference date into the method. This makes the result reproducible and avoids changing system time.
import java.time.LocalDate;
public static int ageOnDate(LocalDate birthDate, LocalDate referenceDate) {
if (birthDate.isAfter(referenceDate)) {
throw new IllegalArgumentException(
"Birth date cannot be after the reference date."
);
}
int age = referenceDate.getYear() - birthDate.getYear();
if (referenceDate.getMonthValue() < birthDate.getMonthValue()
|| (referenceDate.getMonthValue() == birthDate.getMonthValue()
&& referenceDate.getDayOfMonth() < birthDate.getDayOfMonth())) {
age--;
}
return age;
}
LocalDate dob = LocalDate.of(2001, 9, 25);
LocalDate cutoff = LocalDate.of(2026, 9, 21);
System.out.println(ageOnDate(dob, cutoff));
This pattern is particularly useful for forms and eligibility checks because the program can preserve the exact reference date used for the calculation.

Calculate exact age in years, months and days
If the output needs to say “31 years, 1 month, 4 days,” use Java’s Period. Oracle documents Period.between(startDateInclusive, endDateExclusive) as a way to obtain years, months, and days between two dates.
import java.time.LocalDate;
import java.time.Period;
LocalDate birthDate = LocalDate.of(1995, 8, 21);
LocalDate referenceDate = LocalDate.of(2026, 9, 21);
Period age = Period.between(birthDate, referenceDate);
System.out.println(age.getYears() + " years, "
+ age.getMonths() + " months, "
+ age.getDays() + " days");
Period is different from a simple integer age. It represents the calendar period in years, months, and days. The end date is exclusive in the documented between() calculation, and the result is based on calendar components rather than a fixed number of days per year.
Period versus manual year calculation
| Approach | Best for | Typical output |
|---|---|---|
| Manual birthday comparison | Completed age in years | 31 |
Period.between() | Calendar components | 31 years, 1 month, 4 days |
ChronoUnit.DAYS.between() | Elapsed whole days | Total days |
ChronoUnit.MONTHS.between() | Complete calendar months | Total months |
Validate a DOB entered as text
When a date of birth comes from a form, CSV file, API, or command line, parse it before calculating age. Java’s LocalDate.parse() can parse an ISO-style date such as 2000-05-10 using the standard ISO date format.
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
public static LocalDate parseDob(String value) {
try {
LocalDate dob = LocalDate.parse(value);
if (dob.isAfter(LocalDate.now())) {
throw new IllegalArgumentException(
"Date of birth cannot be in the future."
);
}
return dob;
} catch (DateTimeParseException ex) {
throw new IllegalArgumentException(
"Enter DOB as YYYY-MM-DD.", ex
);
}
}
For a production form, you can use a DateTimeFormatter when a different input format is required. Keep parsing and validation separate from the age calculation so the core method remains easy to test.
Calculate total days since birth
Sometimes the requirement is total elapsed days rather than completed age. Java’s ChronoUnit.DAYS.between() is suitable for that measurement.
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
LocalDate birthDate = LocalDate.of(2000, 5, 10);
LocalDate today = LocalDate.now();
long totalDays = ChronoUnit.DAYS.between(birthDate, today);
System.out.println("Total days: " + totalDays);
Do not turn total days into age by blindly dividing by 365 or 365.25. Leap years and calendar boundaries mean elapsed duration and birthday-based age are different measurements.
Calculate total months or years
Java’s date API can also measure a whole-unit difference. The choice of unit matters: complete months are not the same as “years times 12,” and the result depends on the start and end dates.
long totalMonths =
ChronoUnit.MONTHS.between(birthDate, today);
long totalYears =
ChronoUnit.YEARS.between(birthDate, today);
System.out.println("Total months: " + totalMonths);
System.out.println("Complete years: " + totalYears);
Oracle notes that unit-based calculations return whole units between the dates. For example, a period that is one day short of two complete months is counted as one month when measured in months.
Leap years and February 29
Leap-day birthdays deserve an explicit policy when a program must decide what happens in a non-leap year. A general age calculator should not silently assume that February 29 always maps to February 28 or March 1. If an application is checking a legal, employment, examination, or contractual rule, use the rule specified by the relevant authority.
| Requirement | Java approach |
|---|---|
| Completed age | Compare month/day after subtracting birth year from reference year |
| Years-months-days | Use Period.between() |
| Eligibility cutoff | Pass the official cutoff as the reference date |
| Elapsed days | Use ChronoUnit.DAYS.between() |
| Feb 29 policy | Define the application’s non-leap-year convention explicitly |
Build a reusable Java age-calculator method
import java.time.LocalDate;
public final class AgeCalculator {
private AgeCalculator() {
}
public static int calculateAge(
LocalDate birthDate,
LocalDate referenceDate) {
if (birthDate == null || referenceDate == null) {
throw new IllegalArgumentException(
"Both dates are required."
);
}
if (birthDate.isAfter(referenceDate)) {
throw new IllegalArgumentException(
"Birth date cannot be after the reference date."
);
}
int age = referenceDate.getYear() - birthDate.getYear();
if (referenceDate.getMonthValue() < birthDate.getMonthValue()
|| (referenceDate.getMonthValue()
== birthDate.getMonthValue()
&& referenceDate.getDayOfMonth()
< birthDate.getDayOfMonth())) {
age--;
}
return age;
}
}
Keeping the reference date as an argument makes this method reusable in desktop applications, Spring services, REST APIs, command-line programs, and automated tests. The calculation itself does not need to know where the dates came from.
Simple command-line age calculator in Java
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.Scanner;
public class AgeCalculatorApp {
public static int calculateAge(
LocalDate birthDate,
LocalDate referenceDate) {
if (birthDate.isAfter(referenceDate)) {
throw new IllegalArgumentException(
"Birth date cannot be in the future."
);
}
int age = referenceDate.getYear() - birthDate.getYear();
if (referenceDate.getMonthValue() < birthDate.getMonthValue()
|| (referenceDate.getMonthValue()
== birthDate.getMonthValue()
&& referenceDate.getDayOfMonth()
< birthDate.getDayOfMonth())) {
age--;
}
return age;
}
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
System.out.print("Enter DOB (YYYY-MM-DD): ");
String input = scanner.nextLine();
LocalDate dob = LocalDate.parse(input);
int age = calculateAge(dob, LocalDate.now());
System.out.println("Age: " + age);
} catch (DateTimeParseException ex) {
System.out.println(
"Please enter a valid date in YYYY-MM-DD format."
);
} catch (IllegalArgumentException ex) {
System.out.println(ex.getMessage());
}
}
}
Common Java age-calculator mistakes
- Subtracting years only: this reports one extra year before the birthday.
- Dividing elapsed days by 365: this ignores calendar birthdays and leap years.
- Using the system clock for every calculation: pass a reference date for fixed eligibility cutoffs and tests.
- Accepting future DOBs: reject a birth date after the reference date.
- Confusing Period with elapsed days:
Periodrepresents calendar years, months, and days, while day counts represent elapsed duration. - Ignoring leap-day rules: document the convention when February 29 matters.
- Using date-time types unnecessarily: use
LocalDatewhen the problem is date-only.
LocalDate, Period and ChronoUnit: which should you use?
| Java type or API | Use it for | Example |
|---|---|---|
LocalDate | Date-only values | DOB or cutoff date |
Period | Calendar components | 31 years, 1 month, 4 days |
ChronoUnit.DAYS | Whole elapsed days | Total days since DOB |
ChronoUnit.MONTHS | Whole calendar months | Total complete months |
ChronoUnit.YEARS | Whole calendar years | Complete years |
Testing an age calculator
Age logic should be tested at the boundaries. Test the day before a birthday, the birthday itself, the day after, a future DOB, month-end dates, and any February 29 behavior your application supports.
import java.time.LocalDate;
assert calculateAge(
LocalDate.of(2000, 5, 10),
LocalDate.of(2026, 5, 9)
) == 25;
assert calculateAge(
LocalDate.of(2000, 5, 10),
LocalDate.of(2026, 5, 10)
) == 26;
assert calculateAge(
LocalDate.of(2000, 5, 10),
LocalDate.of(2026, 5, 11)
) == 26;
Frequently asked questions
Can Java calculate age without an external library?
Yes. Java's standard java.time API is enough for completed age, calendar periods, and elapsed date differences.
What is the simplest Java age formula?
Subtract the birth year from the reference year, then subtract one if the reference month and day occur before the birthday.
Can I calculate age on a past date?
Yes. Pass that date as the reference date. This is useful for historical records and fixed eligibility cutoffs.
What does Period.between() return?
It returns a Period containing calendar years, months, and days between the two dates. Use its getters when you need each component separately.
Should I use LocalDate or LocalDateTime for a DOB?
Use LocalDate when the requirement is only the date of birth. Use a date-time type only when time of day is genuinely part of the calculation.
Final takeaway
A reliable age calculator in Java can be built entirely with the standard java.time API. Use LocalDate for DOB and reference dates, compare the birthday to calculate completed years, use Period.between() for years-months-days, and use ChronoUnit when the requirement is a whole-unit duration. Keeping the reference date explicit makes the same logic useful for testing and eligibility calculations.