Duration Class

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

java.time.Duration represents an exact amount of time, measured in seconds and nanoseconds, such as "2 hours 15 minutes" or "1.5 seconds." It is the right type for elapsed time and machine-scale intervals: request latency, timeouts, session lengths, cache expiry, retry delays, video lengths, and shift hours. Unlike Period, a Duration is not tied to the calendar: one day in a Duration is always exactly 24 hours.

Creating a Duration

import java.time.Duration;
import java.time.temporal.ChronoUnit;

Duration.ofMinutes(135);              // PT2H15M
Duration.ofSeconds(90);               // PT1M30S
Duration.ofMillis(1500);              // PT1.5S
Duration.ofHours(8);                  // PT8H
Duration.ofDays(2);                   // PT48H: always 48 hours
Duration.of(3, ChronoUnit.HALF_DAYS); // PT36H
Duration.parse("PT1H30M");            // from ISO-8601 text
Duration.ZERO;                        // PT0S

The ISO-8601 form starts with PT (period of time) followed by hours (H), minutes (M), and seconds (S, with an optional fraction). toString() produces it, and parse reads it, which makes durations easy to store in configuration files: session.timeout=PT30M.

Measuring Between Two Values

Duration.between(LocalTime.of(9, 15), LocalTime.of(17, 45));        // PT8H30M

Instant t1 = Instant.parse("2026-11-13T10:00:00Z");
Instant t2 = Instant.parse("2026-11-13T10:00:01.250Z");
Duration.between(t1, t2);                                           // PT1.25S

Duration.between works with time-based types: Instant, LocalTime, LocalDateTime, ZonedDateTime, and OffsetDateTime. It does not work with LocalDate, which has no time of day:

Duration.between(LocalDate.of(2026, 1, 1), LocalDate.of(2026, 1, 2));
// UnsupportedTemporalTypeException

For dates, use Period.between or ChronoUnit.DAYS.between.

The result is negative if the second argument is earlier than the first: Duration.ofSeconds(-90) prints as PT-1M-30S.

Measuring elapsed time in code

long start = System.nanoTime();
runReport();
Duration elapsed = Duration.ofNanos(System.nanoTime() - start);

For measuring how long code takes, use System.nanoTime(), which is monotonic: it cannot jump if the system clock is adjusted. Instant.now() is for knowing what time it is, not for timing operations.

Converting and Reading Parts

Two families of methods extract values, and confusing them is a common error:

Method familyReturnsDuration.ofMinutes(135)
toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos()The total amount in that unittoHours() → 2, toMinutes() → 135
toDaysPart(), toHoursPart(), toMinutesPart(), toSecondsPart(), toMillisPart()The component of that unit (Java 9+)toHoursPart() → 2, toMinutesPart() → 15

To display "2h 15m," use toHours() and toMinutesPart(). Using toMinutes() would print "2h 135m." The to*Part methods are designed exactly for building such displays:

Duration.ofHours(25).toDaysPart();     // 1
Duration.ofHours(25).toHoursPart();    // 1

getSeconds() returns the total seconds and getNano() the nanosecond remainder, matching how a Duration is stored internally.

Arithmetic

Durations are immutable; every operation returns a new one:

Duration.ofHours(1).plusMinutes(15).multipliedBy(3);         // PT3H45M
Duration.ofMinutes(100).dividedBy(4);                        // PT25M
Duration.ofMinutes(100).dividedBy(Duration.ofMinutes(30));   // 3: how many whole 30-minute blocks
Duration.ofMinutes(10).minus(Duration.ofSeconds(30));        // PT9M30S
Duration.ofSeconds(3725).truncatedTo(ChronoUnit.MINUTES);    // PT1H2M
Duration.ofSeconds(-90).abs();                               // PT1M30S

dividedBy(long) truncates any fraction of a nanosecond; dividedBy(Duration) (Java 9+) returns a whole count.

Comparing

Duration slo = Duration.ofSeconds(2);
Duration latency = Duration.ofMillis(2300);

latency.compareTo(slo) > 0;     // true: slower than the target
latency.isNegative();           // false
Duration.ZERO.isZero();         // true

Duration implements Comparable, so latencies can be sorted and the slowest found with Collections.max.

Applying a Duration

Instant now = Instant.parse("2026-11-13T10:00:00Z");
Instant expires = now.plus(Duration.ofMinutes(30));          // 2026-11-13T10:30:00Z

LocalTime.of(23, 30).plus(Duration.ofHours(2));              // 01:30 (wraps around midnight)
ZonedDateTime.now().plus(Duration.ofDays(1));                // exactly 24 hours later, even across DST

On a ZonedDateTime, plus(Duration.ofDays(1)) adds 24 real hours, while plus(Period.ofDays(1)) moves to the same local time on the next calendar day. On the night clocks change for daylight-saving time, those two results differ by an hour.

Duration in APIs

Many Java APIs accept a Duration directly, which avoids ambiguous plain numbers ("is this 5000 milliseconds or seconds?"):

HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5));
HttpRequest.newBuilder(uri).timeout(Duration.ofSeconds(10));
Thread.sleep(Duration.ofMillis(500));                        // Java 19+

Accepting Duration parameters in your own methods makes call sites self-explanatory.

Practical Example: Latency Reports and Session Expiry

A backend service tracks request latencies against a two-second service-level objective (SLO), and expires user sessions after 30 minutes of inactivity or 8 hours in total, whichever comes first.

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

public class Dur {
    static String human(Duration d) {
        if (d.isNegative()) return "-" + human(d.negated());
        if (d.toDays() > 0) return d.toDays() + "d " + d.toHoursPart() + "h";
        if (d.toHours() > 0) return d.toHours() + "h " + d.toMinutesPart() + "m";
        if (d.toMinutes() > 0) return d.toMinutes() + "m " + d.toSecondsPart() + "s";
        return d.toMillis() + " ms";
    }

    public static void main(String[] args) {
        long[] latenciesMs = {120, 85, 2300, 450, 95, 6100, 130};
        Duration slo = Duration.ofSeconds(2);
        Duration total = Duration.ZERO;
        int breaches = 0;
        for (long ms : latenciesMs) {
            Duration lat = Duration.ofMillis(ms);
            total = total.plus(lat);
            if (lat.compareTo(slo) > 0) breaches++;
        }
        System.out.println("Average latency: " + human(total.dividedBy(latenciesMs.length)) + ", SLO breaches: " + breaches);

        Instant login = Instant.parse("2026-11-13T09:15:00Z");
        Duration idleTimeout = Duration.ofMinutes(30), absolute = Duration.ofHours(8);
        Instant lastActivity = Instant.parse("2026-11-13T16:50:00Z");
        Instant now = Instant.parse("2026-11-13T17:10:00Z");
        Instant expires = Collections.min(List.of(lastActivity.plus(idleTimeout), login.plus(absolute)));
        System.out.println("Session expires at " + expires + ", time left " + human(Duration.between(now, expires)));
        System.out.println(human(Duration.ofHours(53)) + " | " + human(Duration.ofSeconds(-125)));
    }
}

Output:

Average latency: 1325 ms, SLO breaches: 2
Session expires at 2026-11-13T17:15:00Z, time left 5m 0s
2d 5h | -2m 5s

The latency report accumulates Durations with plus, averages them with dividedBy, and counts requests slower than the SLO with compareTo: two requests (2.3 s and 6.1 s) breach the 2-second target. The session check computes two candidate expiry instants, 30 minutes after the last activity (17:20) and 8 hours after login (17:15), and takes the earlier one with Collections.min, since Instant is comparable. human turns any duration into a short readable string by picking the largest relevant unit and pairing a to* total with the matching to*Part component; it handles negative durations by formatting the absolute value with a minus sign.

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 Duration Class and get answers drawn from it.

Signed-in readers only.