Back to Blog
Java

Java Duration Between: Calculating Elapsed Time

java duration between: Learn how to use Duration.between to measure time intervals between LocalDateTime, LocalTime, and Instant in Java, including time zone and edge...

java.timeDurationLocalDateTimeInstanttime measurementChronoUnit
A clock face with two highlighted time markers and an arrow showing the duration between them, representing Java's Duration.between calculation.

Calculating the elapsed time between two points is a common requirement in Java applications. The java.time package provides Duration for time-based measurements, and the Duration.between method is the primary way to obtain a duration between two temporal objects. This article explains how to use java duration between correctly, covering the main temporal types, time zone behavior, and common mistakes.

Using Duration.between for Time-Based Differences

The Duration.between method accepts two Temporal arguments and returns a Duration representing the time between them. The signature is:

public static Duration between(Temporal startInclusive, Temporal endExclusive)

The method works with any temporal type that supports time-based fields, such as LocalTime, LocalDateTime, Instant, and ZonedDateTime. It does not work with date-only types like LocalDate because Duration measures seconds and nanoseconds, not calendar days.

Here is a basic example using LocalDateTime:

LocalDateTime start = LocalDateTime.of(2025, 3, 10, 9, 30); LocalDateTime end = LocalDateTime.of(2025, 3, 10, 11, 45); Duration duration = Duration.between(start, end); System.out.println(duration.toMinutes()); // 135

The Duration object stores the total elapsed time as seconds plus a nanosecond adjustment. The toMinutes() method returns the whole minutes in the duration, truncating any remaining seconds or nanoseconds.

Choosing Between LocalDateTime and Instant

A key decision is which temporal type to use as the source and target for Duration.between. LocalDateTime has no time zone information; it represents a date and time as if viewed on a wall clock. Instant represents a specific point on the time line, measured in seconds and nanoseconds since the Unix epoch.

If you are measuring elapsed time for something like a timer or a network request, Instant is usually the right choice because it is absolute. Using LocalDateTime can produce misleading results when the start and end times come from different time zones or when a daylight saving time transition occurs between them.

Instant start = Instant.parse("2025-03-08T10:00:00Z"); Instant end = Instant.parse("2025-03-08T12:00:00Z"); Duration duration = Duration.between(start, end); System.out.println(duration.toHours()); // 2

If you use LocalDateTime with values that were originally in different zones, you lose the offset information and the calculated duration may not reflect actual elapsed time. Use ZonedDateTime when you need to preserve the zone context.

Working with LocalTime and Duration Over Midnight

Duration.between also works with LocalTime. A common pitfall occurs when the interval crosses midnight. For example, from 23:30 to 01:15 should be 1 hour and 45 minutes, but a naive call returns a negative duration because LocalTime has no date component.

LocalTime start = LocalTime.of(23, 30); LocalTime end = LocalTime.of(1, 15); Duration duration = Duration.between(start, end); System.out.println(duration.toMinutes()); // -1350

To handle this correctly, you must detect the wrap-around and add one day to the end time. A common approach is to use LocalTime with LocalDate or to adjust the end time manually:

LocalTime start = LocalTime.of(23, 30); LocalTime end = LocalTime.of(1, 15); Duration duration; if (end.isBefore(start)) { duration = Duration.between(start, end.plusHours(24)); } else { duration = Duration.between(start, end); } System.out.println(duration.toMinutes()); // 105

Alternatively, use LocalDateTime with explicit dates to avoid the ambiguity entirely.

Converting Duration to Days, Hours, Minutes, and Seconds

Duration provides several methods to extract the whole-number components: toDays(), toHours(), toMinutes(), toSeconds(), and toMillis(). These methods truncate the duration to the requested unit. For example, a duration of 25 hours and 30 minutes has toHours() equal to 25, not 1 day and 1 hour.

If you need the individual components (days, hours, minutes, seconds) separately, you can compute them by dividing and taking remainders:

Duration duration = Duration.ofHours(26).plusMinutes(15); long days = duration.toDays(); long hours = duration.toHours() % 24; long minutes = duration.toMinutes() % 60; long seconds = duration.getSeconds() % 60;

This is a common pattern when formatting a duration for display. The getSeconds() method returns the total seconds, which includes the days and hours, so the modulo operation extracts the remainder.

Comparing Duration with Period for Date-Based Differences

Duration is designed for time-based amounts measured in hours, minutes, seconds, and nanoseconds. For date-based amounts like years, months, and days, Java provides Period. The two classes are not interchangeable.

For example, if you want the number of calendar days between two dates, Duration.between is not appropriate because it treats a day as exactly 24 hours. Daylight saving transitions can make a calendar day 23 or 25 hours long. Instead, use ChronoUnit.DAYS.between or Period.between for date-only calculations.

LocalDate startDate = LocalDate.of(2025, 3, 1); LocalDate endDate = LocalDate.of(2025, 3, 15); long days = ChronoUnit.DAYS.between(startDate, endDate); // 14

Use Duration when you need precise elapsed time in seconds or nanoseconds, and Period when you need calendar-based differences like months or years.

Handling Time Zones When Measuring Duration

When using ZonedDateTime, Duration.between accounts for the actual offset at each point in time. This means the result reflects real elapsed time, not just the wall-clock difference. This is especially important around daylight saving time transitions.

ZonedDateTime start = ZonedDateTime.of(2025, 3, 9, 1, 30, 0, 0, ZoneId.of("America/New_York")); ZonedDateTime end = ZonedDateTime.of(2025, 3, 9, 3, 30, 0, 0, ZoneId.of("America/New_York")); Duration duration = Duration.between(start, end); System.out.println(duration.toHours()); // 1, not 2

In this example, the clocks spring forward by one hour, so the elapsed time is only one hour even though the local times differ by two hours. Duration.between correctly returns 1 hour. If you used LocalDateTime instead, you would get 2 hours, which is inaccurate for measuring real time.

Common Pitfalls and Edge Cases with Duration.between

Several edge cases can trip up developers. First, if the start is after the end, Duration.between returns a negative duration. This is by design, but you may need to check and handle it depending on your use case.

Second, Duration.between throws DateTimeException if the temporal types do not support time-based fields. For example, calling it with two LocalDate instances fails because LocalDate does not have a time component.

Third, the precision of the result depends on the input types. Instant and LocalDateTime support nanosecond precision, while LocalTime also supports nanoseconds. If you use ZonedDateTime, the result includes the full precision of the underlying instant.

Finally, be careful when using Duration.between with LocalTime and crossing midnight, as shown earlier. Always consider whether the interval might wrap around and adjust the end time accordingly.

Performance and Maintainability Considerations

Creating a Duration object is inexpensive; it is an immutable value class that stores two long fields. In most applications, the cost of calling Duration.between is negligible compared to the surrounding logic. However, if you are measuring time in a tight loop, avoid unnecessary allocations by reusing the same Duration instance when possible, or by using primitive arithmetic with System.nanoTime() for high-frequency timing.

For maintainability, prefer Duration over manual arithmetic when you need to represent a time interval. The class provides clear methods for conversion and comparison, reducing the chance of off-by-one errors. When you only need the difference in a single unit, ChronoUnit.between can be more concise:

long minutes = ChronoUnit.MINUTES.between(start, end);

This returns the same value as Duration.between(start, end).toMinutes() but avoids creating a Duration object. Use this when you do not need the full Duration object for further operations.

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