src/share/classes/java/time/Duration.java
Print this page
@@ -83,10 +83,11 @@
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
@@ -300,35 +301,36 @@
return ZERO.plus(amount, unit);
}
//-----------------------------------------------------------------------
/**
- * Obtains a {@code Duration} representing the duration between two instants.
- * <p>
- * This calculates the duration between two temporal objects of the same type.
- * The difference in seconds is calculated using
- * {@link Temporal#periodUntil(Temporal, TemporalUnit)}.
- * The difference in nanoseconds is calculated using by querying the
- * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field.
+ * Obtains an instance of {@code Duration} from a temporal amount.
* <p>
- * The result of this method can be a negative period if the end is before the start.
- * To guarantee to obtain a positive duration call {@link #abs()} on the result.
- *
- * @param startInclusive the start instant, inclusive, not null
- * @param endExclusive the end instant, exclusive, not null
- * @return a {@code Duration}, not null
- * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
- */
- public static Duration between(Temporal startInclusive, Temporal endExclusive) {
- long secs = startInclusive.periodUntil(endExclusive, SECONDS);
- long nanos;
- try {
- nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
- } catch (DateTimeException ex) {
- nanos = 0;
+ * This obtains a duration based on the specified amount.
+ * A {@code TemporalAmount} represents an amount of time, which may be
+ * date-based or time-based, which this factory extracts to a duration.
+ * <p>
+ * The conversion loops around the set of units from the amount and uses
+ * the {@linkplain TemporalUnit#getDuration() duration} of the unit to
+ * calculate the total {@code Duration}.
+ * Only a subset of units are accepted by this method. The unit must either
+ * have an {@linkplain TemporalUnit#isDurationEstimated() exact duration}
+ * or be {@link ChronoUnit#DAYS} which is treated as 24 hours.
+ * If any other units are found then an exception is thrown.
+ *
+ * @param amount the temporal amount to convert, not null
+ * @return the equivalent duration, not null
+ * @throws DateTimeException if unable to convert to a {@code Duration}
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public static Duration from(TemporalAmount amount) {
+ Objects.requireNonNull(amount, "amount");
+ Duration duration = ZERO;
+ for (TemporalUnit unit : amount.getUnits()) {
+ duration = duration.plus(amount.get(unit), unit);
}
- return ofSeconds(secs, nanos);
+ return duration;
}
//-----------------------------------------------------------------------
/**
* Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}.
@@ -358,18 +360,18 @@
* The leading plus/minus sign, and negative values for other units are
* not part of the ISO-8601 standard.
* <p>
* Examples:
* <pre>
- * "PT20.345S" -> parses as "20.345 seconds"
- * "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds)
- * "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds)
- * "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds)
- * "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes"
- * "P-6H3M" -> parses as "-6 hours and +3 minutes"
- * "-P6H3M" -> parses as "-6 hours and -3 minutes"
- * "-P-6H+3M" -> parses as "+6 hours and -3 minutes"
+ * "PT20.345S" -- parses as "20.345 seconds"
+ * "PT15M" -- parses as "15 minutes" (where a minute is 60 seconds)
+ * "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds)
+ * "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
+ * "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes"
+ * "P-6H3M" -- parses as "-6 hours and +3 minutes"
+ * "-P6H3M" -- parses as "-6 hours and -3 minutes"
+ * "-P-6H+3M" -- parses as "+6 hours and -3 minutes"
* </pre>
*
* @param text the text to parse, not null
* @return the parsed duration, not null
* @throws DateTimeParseException if the text cannot be parsed to a duration
@@ -437,10 +439,48 @@
return ofSeconds(seconds, nanos);
}
//-----------------------------------------------------------------------
/**
+ * Obtains a {@code Duration} representing the duration between two instants.
+ * <p>
+ * This calculates the duration between two temporal objects of the same type.
+ * The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit.
+ * For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the
+ * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
+ * <p>
+ * The result of this method can be a negative period if the end is before the start.
+ * To guarantee to obtain a positive duration call {@link #abs()} on the result.
+ *
+ * @param startInclusive the start instant, inclusive, not null
+ * @param endExclusive the end instant, exclusive, not null
+ * @return a {@code Duration}, not null
+ * @throws DateTimeException if the seconds between the temporals cannot be obtained
+ * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
+ */
+ public static Duration between(Temporal startInclusive, Temporal endExclusive) {
+ try {
+ return ofNanos(startInclusive.periodUntil(endExclusive, NANOS));
+ } catch (DateTimeException | ArithmeticException ex) {
+ long secs = startInclusive.periodUntil(endExclusive, SECONDS);
+ long nanos;
+ try {
+ nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
+ if (secs > 0 && nanos < 0) {
+ secs++;
+ } else if (secs < 0 && nanos > 0) {
+ secs--;
+ }
+ } catch (DateTimeException ex2) {
+ nanos = 0;
+ }
+ return ofSeconds(secs, nanos);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
* Obtains an instance of {@code Duration} using seconds and nanoseconds.
*
* @param seconds the length of the duration in seconds, positive or negative
* @param nanoAdjustment the nanosecond adjustment within the second, from 0 to 999,999,999
*/
@@ -472,19 +512,20 @@
* All other units throw an exception.
*
* @param unit the {@code TemporalUnit} for which to return the value
* @return the long value of the unit
* @throws DateTimeException if the unit is not supported
+ * @throws UnsupportedTemporalTypeException if the unit is not supported
*/
@Override
public long get(TemporalUnit unit) {
if (unit == SECONDS) {
return seconds;
} else if (unit == NANOS) {
return nanos;
} else {
- throw new DateTimeException("Unsupported unit: " + unit.getName());
+ throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
}
/**
* Gets the set of units supported by this duration.
@@ -635,19 +676,20 @@
* This instance is immutable and unaffected by this method call.
*
* @param amountToAdd the amount of the period, measured in terms of the unit, positive or negative
* @param unit the unit that the period is measured in, must have an exact duration, not null
* @return a {@code Duration} based on this duration with the specified duration added, not null
+ * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public Duration plus(long amountToAdd, TemporalUnit unit) {
Objects.requireNonNull(unit, "unit");
if (unit == DAYS) {
return plus(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY), 0);
}
if (unit.isDurationEstimated()) {
- throw new DateTimeException("Unit must not have an estimated duration");
+ throw new UnsupportedTemporalTypeException("Unit must not have an estimated duration");
}
if (amountToAdd == 0) {
return this;
}
if (unit instanceof ChronoUnit) {
@@ -1128,13 +1170,13 @@
*
* @return the total length of the duration in nanoseconds
* @throws ArithmeticException if numeric overflow occurs
*/
public long toNanos() {
- long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND);
- millis = Math.addExact(millis, nanos);
- return millis;
+ long totalNanos = Math.multiplyExact(seconds, NANOS_PER_SECOND);
+ totalNanos = Math.addExact(totalNanos, nanos);
+ return totalNanos;
}
//-----------------------------------------------------------------------
/**
* Compares this duration to the specified {@code Duration}.
@@ -1197,14 +1239,14 @@
* If a section has a zero value, it is omitted.
* The hours, minutes and seconds will all have the same sign.
* <p>
* Examples:
* <pre>
- * "20.345 seconds" -> "PT20.345S
- * "15 minutes" (15 * 60 seconds) -> "PT15M"
- * "10 hours" (10 * 3600 seconds) -> "PT10H"
- * "2 days" (2 * 86400 seconds) -> "PT48H"
+ * "20.345 seconds" -- "PT20.345S
+ * "15 minutes" (15 * 60 seconds) -- "PT15M"
+ * "10 hours" (10 * 3600 seconds) -- "PT10H"
+ * "2 days" (2 * 86400 seconds) -- "PT48H"
* </pre>
* Note that multiples of 24 hours are not output as days to avoid confusion
* with {@code Period}.
*
* @return an ISO-8601 representation of this duration, not null