Period Class

Su Suriya Ravichandran Updated 14 Nov 2026
5 min read ·Lesson 120 of 133

java.time.Period represents an amount of time in calendar units: years, months, and days, such as "1 year, 2 months, and 3 days." It is the right type for human-scale, date-based amounts: ages, subscription plans, loan terms, warranty periods, notice periods, and "30 days after the invoice date." Because months and years vary in length, a Period is not a fixed number of seconds; it means "move the calendar forward by this many units." For exact, time-based amounts, use Duration (next lesson).

Creating a Period

import java.time.Period;

Period p = Period.of(1, 2, 3);        // P1Y2M3D: 1 year, 2 months, 3 days
Period.ofYears(1);                    // P1Y
Period.ofMonths(6);                   // P6M
Period.ofWeeks(2);                    // P14D: stored as days
Period.ofDays(45);                    // P45D
Period.parse("P1Y6M");                // from ISO-8601 text
Period.ZERO;                          // P0D

The text form follows ISO-8601: P (period), then a number before Y, M, W, or D. It is what toString() produces and what parse() accepts.

p.getYears();     // 1
p.getMonths();    // 2
p.getDays();      // 3

A Period keeps the three units separately. It does not convert days to months or months to years automatically.

Measuring a Period Between Dates

Period.between(start, end) measures the gap between two LocalDates in years, months, and days, the way a person counts it on a calendar:

LocalDate dob = LocalDate.of(1998, 2, 14);
LocalDate today = LocalDate.of(2026, 11, 13);

Period age = Period.between(dob, today);
age;                 // P28Y8M30D
age.getYears();      // 28: the person's age
age.toTotalMonths(); // 344

The end date is exclusive. If the end is before the start, the result is negative:

Period.between(LocalDate.of(2026, 3, 1), LocalDate.of(2026, 1, 15));   // P-1M-17D

Period versus a day count

Period.between answers "how many years, months, and days?"; ChronoUnit.DAYS.between answers "how many days in total?":

ChronoUnit.DAYS.between(dob, today);    // 10499

A common mistake is to call period.getDays() expecting the total number of days. For P28Y8M30D, getDays() returns 30, only the day component.

Applying a Period to a Date

LocalDate start = LocalDate.of(2026, 1, 31);

start.plus(Period.ofMonths(1));       // 2026-02-28: month-end clamped
start.plus(Period.ofDays(30));        // 2026-03-02
start.minus(Period.ofYears(1));       // 2025-01-31

plus(Period) adds years first, then months, then days, adjusting to a valid date after the month step. "One month" and "30 days" give different results because months differ in length, which is exactly why both units exist.

Normalization and Equality

Period.ofMonths(14).normalized();     // P1Y2M: months over 11 become years
Period.ofDays(45).normalized();       // P45D: days are never converted (months vary in length)

equals compares the three fields individually, so periods that represent "the same" amount in different units are not equal:

Period.of(0, 12, 0).equals(Period.ofYears(1));    // false
Period.ofMonths(1).equals(Period.ofDays(30));     // false

Normalize before comparing when years and months should be considered interchangeable. Days and months are never interchangeable.

Other useful methods: isZero(), isNegative(), negated(), multipliedBy(n), plusMonths(n), withDays(n).

Period with ZonedDateTime

Applied to a ZonedDateTime, a Period keeps the local time of day, even across a daylight-saving change, whereas a Duration adds exact elapsed time:

ZonedDateTime z = ZonedDateTime.of(2026, 3, 7, 12, 0, 0, 0, ZoneId.of("America/New_York"));
z.plus(Period.ofDays(1));      // 2026-03-08T12:00-04:00: same wall-clock time next day
z.plus(Duration.ofDays(1));    // 2026-03-08T13:00-04:00: exactly 24 hours later

The night of 7–8 March 2026 is when New York moves its clocks forward, so that calendar day lasts only 23 hours. Use Period for "same time tomorrow" and Duration for "exactly 24 hours from now."

Period cannot be applied to a LocalTime or an Instant, since neither has a calendar date (Instant.plus(Period.ofDays(1)) works only for days, interpreted as 24 hours, and throws for months and years).

Period Versus Duration

PeriodDuration
UnitsYears, months, daysSeconds and nanoseconds (shown as hours, minutes, seconds)
Based onThe calendarExact elapsed time
ExampleP1Y2M3DPT8H30M
Works withLocalDate, LocalDateTime, ZonedDateTimeTime-based types: LocalTime, LocalDateTime, ZonedDateTime, Instant
Typical useAges, subscriptions, loan termsTimeouts, elapsed time, session lengths

Practical Example: Membership Renewals

A learning platform sells memberships of one month, three months, or one year. The admin dashboard shows each member's renewal date and time left, or how long ago a plan expired.

import java.time.*;
import java.util.List;

public class Per {
    record Member(String name, LocalDate joined, Period plan) { }

    public static void main(String[] args) {
        LocalDate today = LocalDate.of(2026, 11, 13);
        List<Member> members = List.of(
            new Member("Ada", LocalDate.of(2025, 12, 14), Period.ofYears(1)),
            new Member("Linus", LocalDate.of(2026, 8, 31), Period.ofMonths(3)),
            new Member("Grace", LocalDate.of(2026, 10, 5), Period.ofMonths(1))
        );
        for (Member m : members) {
            LocalDate expiry = m.joined().plus(m.plan());
            Period left = Period.between(today, expiry);
            String status = expiry.isBefore(today) ? "expired " + Period.between(expiry, today).getDays() + " day(s) ago"
                    : "renews " + expiry + " (in " + left.getMonths() + "m " + left.getDays() + "d)";
            System.out.println(m.name() + " joined " + m.joined() + ", plan " + m.plan() + ": " + status);
        }
    }
}

Output:

Ada joined 2025-12-14, plan P1Y: renews 2026-12-14 (in 1m 1d)
Linus joined 2026-08-31, plan P3M: renews 2026-11-30 (in 0m 17d)
Grace joined 2026-10-05, plan P1M: expired 8 day(s) ago

Each plan is a Period, so joined.plus(plan) produces the expiry date according to calendar rules. Linus joined on 31 August; three months later would be 31 November, which does not exist, so the date is clamped to 30 November rather than overflowing into December. Period.between(today, expiry) expresses the time remaining in months and days, which reads naturally on a dashboard. For an expired plan, the period is measured the other way round to report how long ago it ended. Because the expired gap here is under a month, getDays() alone is the full count; a production version would format years and months too, or use ChronoUnit.DAYS.between for a single total.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Period Class and get answers drawn from it.

Signed-in readers only.