java 42 lines · 7 steps

Adding ISO-8601 durations across time zones in Java

A calculator that adds an ISO-8601 duration to an instant, handling calendar units through a zone so DST and month lengths stay correct.

Explained by highlit
1package com.example.time;
2 
3import java.time.Duration;
4import java.time.Instant;
5import java.time.LocalDateTime;
6import java.time.Period;
7import java.time.ZoneId;
8import java.time.format.DateTimeParseException;
9 
10public final class DurationOffsetCalculator {
11 
12 private final ZoneId zone;
13 
14 public DurationOffsetCalculator(ZoneId zone) {
15 this.zone = zone;
16 }
17 
18 public Instant addIso8601(Instant start, String iso8601) {
19 if (iso8601 == null || iso8601.isBlank()) {
20 throw new IllegalArgumentException("duration must not be blank");
21 }
22 
23 int timeIndex = iso8601.indexOf('T');
24 String datePart = timeIndex < 0 ? iso8601 : iso8601.substring(0, timeIndex);
25 boolean hasCalendarUnits = datePart.length() > 1 || datePart.contains("Y") || datePart.contains("M") || datePart.contains("W") || datePart.contains("D");
26 
27 try {
28 if (hasCalendarUnits) {
29 Period period = Period.parse(timeIndex < 0 ? iso8601 : datePart);
30 Duration time = timeIndex < 0 ? Duration.ZERO : Duration.parse("P" + iso8601.substring(timeIndex));
31 return LocalDateTime.ofInstant(start, zone)
32 .plus(period)
33 .plus(time)
34 .atZone(zone)
35 .toInstant();
36 }
37 return start.plus(Duration.parse(iso8601));
38 } catch (DateTimeParseException e) {
39 throw new IllegalArgumentException("invalid ISO-8601 duration: " + iso8601, e);
40 }
41 }
42}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Calendar units like months and days are zone-dependent, so they must be applied through a LocalDateTime rather than a fixed-length Duration.
  2. 2Splitting an ISO-8601 string at 'T' lets you route the date part to Period and the time part to Duration, which parse different halves.
  3. 3Wrapping parse calls to rethrow a domain-specific exception gives callers a clear, uniform failure contract.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Adding ISO-8601 durations across time zones in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code