Back to Blog
Java

Java Period Between Two Dates

java period between: Learn how to use Java's Period.between to compute the calendar difference between two LocalDate instances, with examples and edge cases.

java.timePeriodLocalDatedate arithmeticChronoUnit
Illustration of two calendar dates separated by a period of time in Java

java period between requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When you need to know how many years, months, and days separate two dates in Java, the Period.between method is the direct answer. This method, part of java.time, returns a Period representing the calendar-based difference between two LocalDate instances. It is the standard way to express a span like "2 years, 3 months, and 5 days" without manually breaking down the difference.

How Period.between Works

The Period.between method takes two LocalDate arguments and returns a Period object. The calculation is based on the calendar system, meaning it respects month lengths and leap years. The returned Period has three components: years, months, and days. The method computes the difference in a way that preserves the calendar semantics: it first compares years, then months, then days.

LocalDate start = LocalDate.of(2020, 1, 15); LocalDate end = LocalDate.of(2023, 6, 20); Period period = Period.between(start, end); System.out.println(period.getYears()); // 3 System.out.println(period.getMonths()); // 5 System.out.println(period.getDays()); // 5

In this example, the difference is 3 years, 5 months, and 5 days. The method does not simply subtract the day-of-month values; it accounts for the actual calendar structure. If the end date is earlier in the month than the start date, the calculation borrows from the previous month, as you would when manually subtracting dates.

A Minimal Example with LocalDate

A common use case is calculating a person's age or the time between two events. The following example shows a simple method that prints the period between two dates:

public static void printPeriod(LocalDate start, LocalDate end) { Period period = Period.between(start, end); System.out.printf("Years: %d, Months: %d, Days: %d%n", period.getYears(), period.getMonths(), period.getDays()); }

This method works for any two valid LocalDate values. The Period object is immutable and thread-safe, so it can be shared without concern. The toString method of Period returns a format like P3Y5M5D, which is useful for logging but not for display to end users.

What Period.between Does Not Include

Period.between works only with calendar dates. It ignores time-of-day components, time zones, and daylight saving time transitions. If you pass a LocalDateTime or ZonedDateTime, you must first convert it to a LocalDate using toLocalDate(). For example:

LocalDateTime startDateTime = LocalDateTime.of(2020, 1, 15, 10, 30); LocalDateTime endDateTime = LocalDateTime.of(2023, 6, 20, 14, 45); Period period = Period.between(startDateTime.toLocalDate(), endDateTime.toLocalDate());

This limitation is intentional. Period is designed for human-readable calendar differences, not precise durations of elapsed time. For time-based differences, use Duration or ChronoUnit.between with finer units.

Comparing Period.between with ChronoUnit.between

ChronoUnit.between can compute the difference in a single unit, such as days, months, or years. It returns a long value. The key difference is that Period.between gives you all three components simultaneously, while ChronoUnit gives you one at a time.

long days = ChronoUnit.DAYS.between(start, end); long months = ChronoUnit.MONTHS.between(start, end); long years = ChronoUnit.YEARS.between(start, end);

Use ChronoUnit when you need a single unit for calculations, such as billing cycles or scheduling. Use Period when you want a human-readable breakdown for reports or forms. Note that ChronoUnit.MONTHS.between counts whole months; any remaining days are ignored, whereas Period.between includes the leftover days.

Handling Negative Periods and Reversed Dates

If the end date is before the start date, Period.between returns a negative period. The components are negative, but the normalization rules still apply. For example:

LocalDate start = LocalDate.of(2023, 6, 20); LocalDate end = LocalDate.of(2020, 1, 15); Period period = Period.between(start, end); // period.getYears() = -3, period.getMonths() = -5, period.getDays() = -5

The negative values are consistent with the calendar arithmetic. If you need to know the absolute difference, you can call period.abs() or swap the arguments. Be careful when using abs() because a Period with negative years, months, and days will have all components negated, which is usually what you want.

Using the Resulting Period for Arithmetic

The Period object is not just for display; it can be added to or subtracted from a LocalDate. This is useful for generating recurring dates or validating ranges.

LocalDate original = LocalDate.of(2021, 3, 10); Period period = Period.of(1, 2, 3); // 1 year, 2 months, 3 days LocalDate result = original.plus(period); System.out.println(result); // 2022-05-13

When you add a Period to a date, the years are added first, then months, then days. This order matters for month-end dates. For example, adding one month to January 31 yields February 28 (or 29 in a leap year), not a non-existent February 31. The LocalDate class handles this by adjusting the day to the last valid day of the target month.

Edge Cases: Month-End Dates and Leap Years

Period.between handles month-end and leap-year cases in a predictable way. Consider the period between January 31 and February 28 in a non-leap year:

LocalDate start = LocalDate.of(2021, 1, 31); LocalDate end = LocalDate.of(2021, 2, 28); Period period = Period.between(start, end); System.out.println(period); // P28D

The result is 28 days, not 1 month. This is because the day-of-month in the start date (31) is greater than the end date's day-of-month (28), so the calculation treats it as a day difference rather than a month difference. If the end date were March 31, the period would be 2 months exactly.

Leap years are handled naturally because LocalDate knows the actual length of February. The period between February 28 and March 28 in a leap year is one month, while the period between February 29 and March 29 is also one month. The method does not require special handling.

Performance and Maintainability Notes

Period.between is a lightweight operation that performs a few arithmetic checks and creates a small immutable object. It does not involve any I/O or complex calculations, so it is suitable for high-frequency use in loops or batch processing. The main performance consideration is not the method itself but how you use the resulting Period. If you only need one component, such as the number of years, consider using ChronoUnit.YEARS.between to avoid creating a Period object unnecessarily.

From a maintainability perspective, using Period.between keeps your date-difference logic declarative and readable. It avoids manual month-length tables and leap-year logic, which are common sources of bugs. The method is part of the standard library, so there is no external dependency. When you need to display a human-readable difference, Period is the right abstraction. When you need to perform arithmetic with a fixed number of days, Duration or ChronoUnit may be more appropriate.

A common mistake is to use Period.between with LocalDateTime without converting to LocalDate. This compiles only if you explicitly call toLocalDate(), but the time part is silently ignored. Another mistake is assuming that Period normalizes months to days. It does not; a period of 1 month and 15 days remains as such. If you need a total number of days, convert to a Duration or use ChronoUnit.DAYS.between.

For applications that must handle time zones, remember that Period is time-zone agnostic. If you are calculating the difference between two instants in different zones, convert both to LocalDate in the same zone before calling between. Otherwise, the calendar day boundary may differ, leading to off-by-one errors.

java period between: Practical Usage and Code Examples | RYUSLOG DEV