17.6 Working with Durations
The java.time.Duration class implements a time-based amount of time in terms of seconds and nanoseconds, using a long and an int value for these time units, respectively. Although the Duration class models an amount of time in terms of seconds and nanoseconds, a duration can represent an amount of time in terms of days, hours, and minutes. As these time units have fixed lengths, it makes interoperability between these units possible. The time-based Duration class can be used with the LocalTime and LocalDateTime classes, as these classes have time fields. In contrast, the Period class essentially represents a date-based amount of time in terms of years, months, and days (p. 1057).
The Period and Duration classes are in the same package (java.time) as the temporal classes. The Period and the Duration classes provide similar methods, as they share many of the method prefixes and common methods with the temporal classes (Table 17.2, p. 1026, and Table 17.3, p. 1026). Their objects are immutable and thread-safe. However, there are also differences between the two classes (p. 1072). Familiarity with one would go a long way toward understanding the other.
Creating Durations
Like the Period class, the Duration class provides the static factory methods ofUNIT() to construct durations with different units.
Duration d1 = Duration.ofDays(1L); // PT24H
Duration d2 = Duration.ofHours(24L); // PT24H
Duration d3 = Duration.ofMinutes(24L*60); // PT24H
Duration d4 = Duration.ofSeconds(24L*60*60); // PT24H
Duration d5 = Duration.ofMillis(24L*60*60*1000); // PT24H
Duration d6 = Duration.ofSeconds(24L*60*60 – 1, 1_000_000_000L); // (1) PT24H
Duration d7 = Duration.ofNanos(24L*60*60*1_000_000_000); // (2) PT24H
Duration d8 = Duration.ofNanos(24*60*60*1_000_000_000); // (3) PT-1.857093632S
The durations created above all have a length of 1 day, except for the one in the last declaration statement. Note that the amount specified should be a long value. It is a good defensive practice to always designate the amount as such in order to avoid inadvertent problems if the amount does not fit into an int. The designation L should be placed such that there is no danger of any previous operation in the expression causing a rollover. This problem is illustrated at (3), where the int value of the argument expression is rolled over, as it is greater than Integer.MAX_VALUE.
The statement at (1) above also illustrates that the value of the nanoseconds is adjusted so that it is always between 0 and 999,999,999. The adjustment at (1) results in the value 0 for nanoseconds and the number of seconds being incremented by 1.
Calling the toString() method on the first seven declarations above, the result is the string “PT24H” (a duration of 24 hours), whereas for the last duration at (3), the result string is “PT-1.857093632S”, which clearly indicates that the int amount was not interpreted as intended.
The previous declarations are equivalent to the ones below, where the amount is qualified with a specific unit in the call to the of(value, unit) method.
Duration d11 = Duration.of(1L, ChronoUnit.DAYS); // P24H
Duration d22 = Duration.of(24L, ChronoUnit.HOURS); // P24H
Duration d33 = Duration.of(24L*60, ChronoUnit.MINUTES); // P24H
Duration d44 = Duration.of(24L*60*60, ChronoUnit.SECONDS); // P24H
Duration d88 = Duration.of(24L*60*60*1000, ChronoUnit.MILLIS);// P24H
Duration d77 = Duration.of(24L*60*60*1_000_000_000,
ChronoUnit.NANOS); // P24H
The code snippet below does not create a duration of 8 days—it creates a duration of 24 hours. The first method call is invoked with the class name, and the subsequent method call is on the new Duration object returned as a consequence of the first call. The of() method creates a new Duration object based on its argument.
Duration duration = Duration.ofDays(7).ofHours(24); // PT24H. Logical error.
Like the Period class, we can create a duration that represents the amount of time between two temporal objects by calling the static method between() of the Duration class.
LocalTime startTime = LocalTime.of(14, 30); // 14:30
LocalTime endTime = LocalTime.of(17, 45, 15); // 17:45:15
Duration interval1 = Duration.between(startTime, endTime); // PT3H15M15S
Duration interval2 = Duration.between(endTime, startTime); // PT-3H-15M-15S
Note the exception thrown in the last statement below because a LocalDateTime object cannot be derived from a LocalTime object, whereas the converse is true.
LocalDateTime dateTime = LocalDateTime.of(2021, 4, 28,
17, 45, 15); // 2021-04-28T17:45:15
Duration interval3 = Duration.between(startTime, dateTime); // PT3H15M15S
Duration interval4 = Duration.between(dateTime, startTime); // DateTimeException!
The Duration class also provides the parse() static method to create a duration from a text representation of a duration based on the ISO standard. If the format of the string is not correct, a DateTimeParseException is thrown. Formatting according to the toString() method is shown in parentheses.
Duration da = Duration.parse(“PT3H15M10.1S”);// 3hrs. 15mins. 10.1s.(PT3H15M10.1S)
Duration db = Duration.parse(“PT0.999S”); // 999000000 nanos. (PT0.999S)
Duration dc = Duration.parse(“-PT30S”); // -30 seconds. (PT-30S)
Duration dd = Duration.parse(“P-24D”); // -24 days (PT-576H)
Duration dd = Duration.parse(“P24H”); // Missing T. DateTimeParseException!
static Duration ZERO
This constant defines a Duration of length zero (PT0S).
static Duration ofDays(long days)
static Duration ofHours(long hours)
static Duration ofMinutes(long minutes)
static Duration ofMillis(long millis)
static Duration ofSeconds(long seconds)
static Duration ofSeconds(long seconds, long nanoAdjustment)
static Duration ofNanos(long nanos)
These static factory methods return a Duration representing an amount of time in seconds and nanoseconds that is equivalent to the specified amount, depending on the method. Nanoseconds are implicitly set to zero. The argument value can be negative. Standard definitions of the units are used. Note that the amount is specified as a long value.
static Duration of(long amount, TemporalUnit unit)
This static factory method returns a Duration representing an amount of time in seconds and nanoseconds that is equivalent to the specified amount in the specified temporal unit. The amount is specified as a long value, which can be negative.
Valid ChronoUnit constants to qualify the amount specified in the method call are the following: NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS, and DAYS (p. 1044). These units have a standard or an estimated duration.
static Duration between(Temporal startInclusive, Temporal endExclusive)
This static method returns the duration between two temporal objects that must support the seconds unit and where it is possible to convert the second temporal argument to the first temporal argument type, if necessary. Otherwise, a DateTimeException is thrown. The result of this method can be a negative period if the end temporal is before the start temporal.
String toString()
Returns a text representation of a Duration according to the ISO standard: PThHmMd.dS—that is, h Hours, m Minutes, and d.d Seconds, where the nanoseconds are formatted as a fraction of a second.
static Duration parse(CharSequence text)
This static method returns a Duration parsed from a character sequence. The formats accepted are based on the ISO duration format PTnHnMn.nS—for example, “PT2H3M4.5S” (2 hours, 3 minutes, and 4.5 seconds). A java.time.format.Date-TimeParseException is thrown if the text cannot be parsed to a duration.