Skip to main content

10.2 Period, Duration, and Date Arithmetic

Overview

After learning how to create and read date/time objects, the next step is calculating differences between two dates and working with spans of time. The java.time package provides two dedicated classes for this:

ClassMeasuresUnit Examples
PeriodDate-based amountyears, months, days
DurationTime-based amounthours, minutes, seconds, nanoseconds

1. Adding and Subtracting Dates (plus / minus Methods)

All java.time objects are immutable— every modification returns a new object, leaving the original unchanged.

import java.time.LocalDate;
import java.time.LocalDateTime;

LocalDate today = LocalDate.of(2026, 3, 23);

// Adding
LocalDate after7Days = today.plusDays(7); // 2026-03-30
LocalDate after2Months = today.plusMonths(2); // 2026-05-23
LocalDate afterYear = today.plusYears(1); // 2027-03-23
LocalDate afterWeeks = today.plusWeeks(3); // 2026-04-13

// Subtracting
LocalDate before3Days = today.minusDays(3); // 2026-03-20
LocalDate before1Month = today.minusMonths(1); // 2026-02-23
LocalDate before2Years = today.minusYears(2); // 2024-03-23

System.out.println("After 7 days: " + after7Days);
System.out.println("After 2 months: " + after2Months);
System.out.println("Before 3 days: " + before3Days);

// LocalDateTime has the same methods
LocalDateTime now = LocalDateTime.of(2026, 3, 23, 14, 30, 0);
LocalDateTime after3Hours = now.plusHours(3); // 2026-03-23T17:30
LocalDateTime after90Mins = now.plusMinutes(90); // 2026-03-23T16:00
LocalDateTime before30Secs = now.minusSeconds(30);// 2026-03-23T14:29:30

System.out.println("After 3 hours: " + after3Hours);
System.out.println("After 90 minutes:" + after90Mins);

2. Period — Date-Based Amounts

Period represents a date-based amount of time: years, months, and days. Use it when you care about calendar units rather than exact durations.

Creating a Period

import java.time.Period;
import java.time.LocalDate;

// Explicit construction
Period oneYear = Period.ofYears(1);
Period twoMonths = Period.ofMonths(2);
Period tenDays = Period.ofDays(10);
Period combined = Period.of(1, 6, 15); // 1 year, 6 months, 15 days

System.out.println(oneYear); // P1Y
System.out.println(twoMonths); // P2M
System.out.println(tenDays); // P10D
System.out.println(combined); // P1Y6M15D

// Apply Period to a date
LocalDate today = LocalDate.of(2026, 3, 23);
LocalDate future = today.plus(combined);
System.out.println(future); // 2027-09-07

Period.between() — Difference Between Two Dates

import java.time.LocalDate;
import java.time.Period;

LocalDate start = LocalDate.of(2020, 6, 15);
LocalDate end = LocalDate.of(2026, 3, 23);

Period diff = Period.between(start, end);

System.out.println("Years: " + diff.getYears()); // 5
System.out.println("Months: " + diff.getMonths()); // 9
System.out.println("Days: " + diff.getDays()); // 8
System.out.println("Total: " + diff); // P5Y9M8D

// Note: getYears/getMonths/getDays are NOT cumulative
// To get total months: use ChronoUnit (shown below)

3. Duration — Time-Based Amounts

Duration represents a time-based amount measured in seconds and nanoseconds. Use it for measuring elapsed time or specifying time spans.

Creating a Duration

import java.time.Duration;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Instant;

// Explicit construction
Duration twoHours = Duration.ofHours(2);
Duration thirtyMins = Duration.ofMinutes(30);
Duration tenSeconds = Duration.ofSeconds(10);
Duration fiveMillis = Duration.ofMillis(500);
Duration combined = Duration.ofHours(2).plusMinutes(30); // 2h 30m

System.out.println(twoHours); // PT2H
System.out.println(thirtyMins); // PT30M
System.out.println(combined); // PT2H30M

// Duration.between()
LocalTime open = LocalTime.of(9, 0);
LocalTime close = LocalTime.of(18, 30);
Duration workHours = Duration.between(open, close);

System.out.println("Work hours: " + workHours.toHours() + "h "
+ workHours.toMinutesPart() + "m"); // Work hours: 9h 30m

// Measuring elapsed time with Instant
Instant start = Instant.now();
// ... computation ...
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
System.out.println("Elapsed: " + elapsed.toMillis() + "ms");

Extracting Duration Parts (Java 9+)

Duration d = Duration.ofHours(2).plusMinutes(45).plusSeconds(30);

// Java 8: toHours() returns total hours (may be large)
System.out.println(d.toHours()); // 2 (total hours)
System.out.println(d.toMinutes()); // 165 (total minutes)
System.out.println(d.toSeconds()); // 9930 (total seconds)

// Java 9+: toPart methods return the component part only
System.out.println(d.toHoursPart()); // 2
System.out.println(d.toMinutesPart()); // 45
System.out.println(d.toSecondsPart()); // 30
System.out.println(d.toMillisPart()); // 0

4. ChronoUnit — Counting in Specific Units

ChronoUnit lets you count the total difference in a single unit (e.g., total days, total hours).

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

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

// Total difference in a single unit
long totalDays = ChronoUnit.DAYS.between(start, end); // 364
long totalWeeks = ChronoUnit.WEEKS.between(start, end); // 52
long totalMonths = ChronoUnit.MONTHS.between(start, end); // 11
long totalYears = ChronoUnit.YEARS.between(start, end); // 0

System.out.println("Days: " + totalDays);
System.out.println("Weeks: " + totalWeeks);
System.out.println("Months: " + totalMonths);

// Works with LocalDateTime too
LocalDateTime from = LocalDateTime.of(2026, 3, 23, 9, 0);
LocalDateTime to = LocalDateTime.of(2026, 3, 23, 17, 30);
long hours = ChronoUnit.HOURS.between(from, to); // 8
long minutes = ChronoUnit.MINUTES.between(from, to); // 510
System.out.println("Hours: " + hours + ", Minutes: " + minutes);

5. TemporalAdjusters — Smart Date Adjustments

TemporalAdjusters provides pre-built strategies for common date adjustments like "first Monday of month" or "next Friday."

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate today = LocalDate.of(2026, 3, 23); // Monday

// First and last day of month
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth()); // 2026-03-01
LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth()); // 2026-03-31
System.out.println("First: " + firstDay + ", Last: " + lastDay);

// First and last day of year
LocalDate firstOfYear = today.with(TemporalAdjusters.firstDayOfYear()); // 2026-01-01
LocalDate lastOfYear = today.with(TemporalAdjusters.lastDayOfYear()); // 2026-12-31

// Next / previous specific weekday
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); // 2026-03-30
LocalDate prevFriday = today.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)); // 2026-03-20
LocalDate nextOrSameMon = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY)); // 2026-03-23 (today!)

// First/last specific weekday in month
LocalDate firstMonday = today.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2026-03-02
LocalDate lastFriday = today.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)); // 2026-03-27

System.out.println("Next Monday: " + nextMonday);
System.out.println("Previous Friday: " + prevFriday);
System.out.println("First Monday: " + firstMonday);
System.out.println("Last Friday: " + lastFriday);

Custom TemporalAdjuster

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjuster;

// Custom: skip to next business day (Mon-Fri)
TemporalAdjuster nextBusinessDay = temporal -> {
LocalDate date = LocalDate.from(temporal);
DayOfWeek dow = date.getDayOfWeek();
int daysToAdd = switch (dow) {
case FRIDAY -> 3; // Friday → Monday
case SATURDAY -> 2; // Saturday → Monday
default -> 1; // Any other day → next day
};
return date.plusDays(daysToAdd);
};

LocalDate friday = LocalDate.of(2026, 3, 27); // Friday
System.out.println(friday.with(nextBusinessDay)); // 2026-03-30 (Monday)

6. Practical Example: D-Day Calculator

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public class DDayCalculator {

public static void main(String[] args) {
// Korean university entrance exam D-Day (example date)
LocalDate examDate = LocalDate.of(2026, 11, 19);
LocalDate today = LocalDate.now();

long daysLeft = ChronoUnit.DAYS.between(today, examDate);

if (daysLeft > 0) {
System.out.println("D-" + daysLeft + " until the exam!");
} else if (daysLeft == 0) {
System.out.println("D-Day! Today is the exam!");
} else {
System.out.println("D+" + Math.abs(daysLeft) + " — exam is past.");
}

// New Year countdown
LocalDate newYear = LocalDate.of(today.getYear() + 1, 1, 1);
long daysToNewYear = ChronoUnit.DAYS.between(today, newYear);
System.out.println(daysToNewYear + " days until New Year " + newYear.getYear());

// Wedding anniversary check
LocalDate anniversary = LocalDate.of(2020, 5, 10);
LocalDate nextAnniv = anniversary.withYear(today.getYear());
if (nextAnniv.isBefore(today) || nextAnniv.isEqual(today)) {
nextAnniv = nextAnniv.plusYears(1);
}
long daysToAnniv = ChronoUnit.DAYS.between(today, nextAnniv);
System.out.println("Next anniversary in " + daysToAnniv + " days: " + nextAnniv);
}
}

7. Practical Example: Work Hours Calculator

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.DayOfWeek;
import java.time.temporal.ChronoUnit;

public class WorkHoursCalculator {

// Count working days between two dates (Mon-Fri only)
public static long countWorkingDays(LocalDate start, LocalDate end) {
long totalDays = ChronoUnit.DAYS.between(start, end);
long workingDays = 0;
for (long i = 0; i < totalDays; i++) {
LocalDate date = start.plusDays(i);
DayOfWeek dow = date.getDayOfWeek();
if (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY) {
workingDays++;
}
}
return workingDays;
}

public static void main(String[] args) {
// Today's work session
LocalDateTime workStart = LocalDateTime.of(2026, 3, 23, 9, 0, 0);
LocalDateTime workEnd = LocalDateTime.of(2026, 3, 23, 18, 30, 0);
Duration lunchBreak = Duration.ofMinutes(60);

Duration totalWork = Duration.between(workStart, workEnd).minus(lunchBreak);
System.out.printf("Work time today: %dh %dm%n",
totalWork.toHours(), totalWork.toMinutesPart()); // 8h 30m

// Working days in Q1 2026
LocalDate q1Start = LocalDate.of(2026, 1, 1);
LocalDate q1End = LocalDate.of(2026, 3, 31);
long workDays = countWorkingDays(q1Start, q1End);
System.out.println("Working days in Q1 2026: " + workDays);

// Probation period end (90 working days from start date)
LocalDate hireDate = LocalDate.of(2026, 1, 5);
long targetWorkDays = 90;
LocalDate probationEnd = hireDate;
long counted = 0;
while (counted < targetWorkDays) {
DayOfWeek dow = probationEnd.getDayOfWeek();
if (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY) {
counted++;
}
if (counted < targetWorkDays) {
probationEnd = probationEnd.plusDays(1);
}
}
System.out.println("Probation ends: " + probationEnd);
}
}

Pro Tips

Period vs Duration — which to use?

  • Period→ calendar-based differences: "How many years/months/days apart?" Used with LocalDate.
  • Duration→ exact time differences: "How many hours/minutes/seconds apart?" Used with LocalTime, LocalDateTime, Instant.
// Period: "1 month later" adjusts for month length differences
LocalDate jan31 = LocalDate.of(2026, 1, 31);
System.out.println(jan31.plus(Period.ofMonths(1))); // 2026-02-28 (not March 3!)

// Duration: "30 days = 30 * 24 hours exactly" regardless of month length
System.out.println(jan31.plusDays(30)); // 2026-03-02

ChronoUnit.DAYS.between() vs Period.between().getDays():

LocalDate start = LocalDate.of(2026, 1, 15);
LocalDate end = LocalDate.of(2026, 3, 10);

// ChronoUnit: total days between — returns 54
long totalDays = ChronoUnit.DAYS.between(start, end);

// Period: calendar breakdown — returns 23 (only the "days" component of 1 month 23 days)
int periodDays = Period.between(start, end).getDays();

System.out.println("ChronoUnit: " + totalDays); // 54
System.out.println("Period.getDays: " + periodDays); // 23

Use ChronoUnit when you need a single total number. Use Period when you want a human-readable breakdown.