Back to Blog
Java

Java Period Between Two Dates

How to use Java's Period.between to compute the calendar difference between two LocalDate values as years, months, and days, with examples and edge cases.

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

Period.between is the java.time method for calculating a calendar-based difference between two LocalDate values. It returns a Period with separate year, month, and day components, so a span like "2 years, 3 months, and 5 days" can be computed without manually handling month lengths or leap years.

How Period.between Works

Period.between takes two LocalDate arguments and returns a Period. The result is a calendar-based span made up of years, months, and days. It respects month lengths and leap years; when an end date's day-of-month is earlier than the start date's day-of-month, the calculation borrows from the preceding month, similar to manual date subtraction.

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.

A Minimal Example with LocalDate

A common use case is calculating a person's age or the time between two events. The following method 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()); }

Period is immutable and thread-safe. Its toString method returns an ISO-8601 value such as P3Y5M5D, which is useful for logging but not usually for display to end users.

What Period.between Does Not Include

Period.between works with calendar dates only and has no time-of-day or time-zone concept. It does not accept a LocalDateTime or ZonedDateTime; convert one of those to LocalDate with toLocalDate() first:

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());

Period is designed for human-readable calendar differences, not precise 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 one unit, such as days, months, or years, and returns a long. Period.between gives you all three components at once, while ChronoUnit gives you one unit 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. 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 sign is the same for all three components. 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

To obtain the absolute calendar difference, swap the arguments or check period.isNegative() and call period.negated(). Period has no abs() method in the standard java.time API.

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 nonexistent 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 predictably. Consider January 31 to 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. Because the start day-of-month (31) is greater than the end day-of-month (28), the calculation treats the leftover as a day difference rather than a complete month. If the end date is March 31, the period is 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, and the period between February 29 and March 29 is also one month.

Practical Notes and Common Mistakes

Period.between keeps date-difference logic declarative and avoids manual month-length and leap-year tables, and it is part of the standard library with no external dependency. If you only need one component, ChronoUnit.between is often more direct and avoids constructing a Period object.

A common mistake is to pass a LocalDateTime to Period.between; that does not compile. Use toLocalDate() first, and remember that the time portion is intentionally ignored. Another mistake is assuming Period normalizes months to days; it does not, so a period of 1 month and 15 days remains 1 month and 15 days. To get a total number of days, anchor the Period to a specific LocalDate and use ChronoUnit.DAYS.between(anchor, anchor.plus(period)), or compare the original dates with ChronoUnit.DAYS.between(start, end).

For applications that must handle time zones, Period is time-zone agnostic. If you are comparing instants in different zones, convert both to LocalDate in the same zone before calling between; otherwise the calendar day boundary can differ, leading to off-by-one errors.

Java Period.between: Calculate Years, Months, and Days Between Dates | RYUSLOG DEV