1 /* 2 * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * * Neither the name of JSR-310 nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.threeten.bp; 33 34 import static org.threeten.bp.LocalTime.SECONDS_PER_DAY; 35 import static org.threeten.bp.LocalTime.SECONDS_PER_HOUR; 36 import static org.threeten.bp.LocalTime.SECONDS_PER_MINUTE; 37 import static org.threeten.bp.temporal.ChronoField.NANO_OF_SECOND; 38 import static org.threeten.bp.temporal.ChronoUnit.DAYS; 39 import static org.threeten.bp.temporal.ChronoUnit.NANOS; 40 import static org.threeten.bp.temporal.ChronoUnit.SECONDS; 41 42 import java.io.DataInput; 43 import java.io.DataOutput; 44 import java.io.IOException; 45 import java.io.InvalidObjectException; 46 import java.io.ObjectStreamException; 47 import java.io.Serializable; 48 import java.math.BigDecimal; 49 import java.math.BigInteger; 50 import java.math.RoundingMode; 51 import java.util.Arrays; 52 import java.util.Collections; 53 import java.util.List; 54 import java.util.regex.Matcher; 55 import java.util.regex.Pattern; 56 57 import org.threeten.bp.format.DateTimeParseException; 58 import org.threeten.bp.jdk8.Jdk8Methods; 59 import org.threeten.bp.temporal.ChronoField; 60 import org.threeten.bp.temporal.ChronoUnit; 61 import org.threeten.bp.temporal.Temporal; 62 import org.threeten.bp.temporal.TemporalAmount; 63 import org.threeten.bp.temporal.TemporalUnit; 64 import org.threeten.bp.temporal.UnsupportedTemporalTypeException; 65 66 /** 67 * A time-based amount of time, such as '34.5 seconds'. 68 * <p> 69 * This class models a quantity or amount of time in terms of seconds and nanoseconds. 70 * It can be accessed using other duration-based units, such as minutes and hours. 71 * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as 72 * exactly equal to 24 hours, thus ignoring daylight savings effects. 73 * See {@link Period} for the date-based equivalent to this class. 74 * <p> 75 * A physical duration could be of infinite length. 76 * For practicality, the duration is stored with constraints similar to {@link Instant}. 77 * The duration uses nanosecond resolution with a maximum value of the seconds that can 78 * be held in a {@code long}. This is greater than the current estimated age of the universe. 79 * <p> 80 * The range of a duration requires the storage of a number larger than a {@code long}. 81 * To achieve this, the class stores a {@code long} representing seconds and an {@code int} 82 * representing nanosecond-of-second, which will always be between 0 and 999,999,999. 83 * <p> 84 * The duration is measured in "seconds", but these are not necessarily identical to 85 * the scientific "SI second" definition based on atomic clocks. 86 * This difference only impacts durations measured near a leap-second and should not affect 87 * most applications. 88 * See {@link Instant} for a discussion as to the meaning of the second and time-scales. 89 * 90 * <h3>Specification for implementors</h3> 91 * This class is immutable and thread-safe. 92 */ 93 public final class Duration 94 implements TemporalAmount, Comparable<Duration>, Serializable { 95 96 /** 97 * Constant for a duration of zero. 98 */ 99 public static final Duration ZERO = new Duration(0, 0); 100 /** 101 * Serialization version. 102 */ 103 private static final long serialVersionUID = 3078945930695997490L; 104 /** 105 * Constant for nanos per second. 106 */ 107 private static final int NANOS_PER_SECOND = 1000000000; 108 /** 109 * Constant for nanos per milli. 110 */ 111 private static final int NANOS_PER_MILLI = 1000000; 112 /** 113 * Constant for nanos per second. 114 */ 115 private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND); 116 /** 117 * The pattern for parsing. 118 */ 119 private final static Pattern PATTERN = 120 Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)D)?" + 121 "(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?", 122 Pattern.CASE_INSENSITIVE); 123 124 /** 125 * The number of seconds in the duration. 126 */ 127 private final long seconds; 128 /** 129 * The number of nanoseconds in the duration, expressed as a fraction of the 130 * number of seconds. This is always positive, and never exceeds 999,999,999. 131 */ 132 private final int nanos; 133 134 //----------------------------------------------------------------------- 135 /** 136 * Obtains an instance of {@code Duration} from a number of standard 24 hour days. 137 * <p> 138 * The seconds are calculated based on the standard definition of a day, 139 * where each day is 86400 seconds which implies a 24 hour day. 140 * The nanosecond in second field is set to zero. 141 * 142 * @param days the number of days, positive or negative 143 * @return a {@code Duration}, not null 144 * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} 145 */ ofDays(long days)146 public static Duration ofDays(long days) { 147 return create(Jdk8Methods.safeMultiply(days, 86400), 0); 148 } 149 150 /** 151 * Obtains an instance of {@code Duration} from a number of standard length hours. 152 * <p> 153 * The seconds are calculated based on the standard definition of an hour, 154 * where each hour is 3600 seconds. 155 * The nanosecond in second field is set to zero. 156 * 157 * @param hours the number of hours, positive or negative 158 * @return a {@code Duration}, not null 159 * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} 160 */ ofHours(long hours)161 public static Duration ofHours(long hours) { 162 return create(Jdk8Methods.safeMultiply(hours, 3600), 0); 163 } 164 165 /** 166 * Obtains an instance of {@code Duration} from a number of standard length minutes. 167 * <p> 168 * The seconds are calculated based on the standard definition of a minute, 169 * where each minute is 60 seconds. 170 * The nanosecond in second field is set to zero. 171 * 172 * @param minutes the number of minutes, positive or negative 173 * @return a {@code Duration}, not null 174 * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} 175 */ ofMinutes(long minutes)176 public static Duration ofMinutes(long minutes) { 177 return create(Jdk8Methods.safeMultiply(minutes, 60), 0); 178 } 179 180 //----------------------------------------------------------------------- 181 /** 182 * Obtains an instance of {@code Duration} from a number of seconds. 183 * <p> 184 * The nanosecond in second field is set to zero. 185 * 186 * @param seconds the number of seconds, positive or negative 187 * @return a {@code Duration}, not null 188 */ ofSeconds(long seconds)189 public static Duration ofSeconds(long seconds) { 190 return create(seconds, 0); 191 } 192 193 /** 194 * Obtains an instance of {@code Duration} from a number of seconds 195 * and an adjustment in nanoseconds. 196 * <p> 197 * This method allows an arbitrary number of nanoseconds to be passed in. 198 * The factory will alter the values of the second and nanosecond in order 199 * to ensure that the stored nanosecond is in the range 0 to 999,999,999. 200 * For example, the following will result in the exactly the same duration: 201 * <pre> 202 * Duration.ofSeconds(3, 1); 203 * Duration.ofSeconds(4, -999_999_999); 204 * Duration.ofSeconds(2, 1000_000_001); 205 * </pre> 206 * 207 * @param seconds the number of seconds, positive or negative 208 * @param nanoAdjustment the nanosecond adjustment to the number of seconds, positive or negative 209 * @return a {@code Duration}, not null 210 * @throws ArithmeticException if the adjustment causes the seconds to exceed the capacity of {@code Duration} 211 */ ofSeconds(long seconds, long nanoAdjustment)212 public static Duration ofSeconds(long seconds, long nanoAdjustment) { 213 long secs = Jdk8Methods.safeAdd(seconds, Jdk8Methods.floorDiv(nanoAdjustment, NANOS_PER_SECOND)); 214 int nos = Jdk8Methods.floorMod(nanoAdjustment, NANOS_PER_SECOND); 215 return create(secs, nos); 216 } 217 218 //----------------------------------------------------------------------- 219 /** 220 * Obtains an instance of {@code Duration} from a number of milliseconds. 221 * <p> 222 * The seconds and nanoseconds are extracted from the specified milliseconds. 223 * 224 * @param millis the number of milliseconds, positive or negative 225 * @return a {@code Duration}, not null 226 */ ofMillis(long millis)227 public static Duration ofMillis(long millis) { 228 long secs = millis / 1000; 229 int mos = (int) (millis % 1000); 230 if (mos < 0) { 231 mos += 1000; 232 secs--; 233 } 234 return create(secs, mos * NANOS_PER_MILLI); 235 } 236 237 /** 238 * Obtains an instance of {@code Duration} from a number of nanoseconds. 239 * <p> 240 * The seconds and nanoseconds are extracted from the specified nanoseconds. 241 * 242 * @param nanos the number of nanoseconds, positive or negative 243 * @return a {@code Duration}, not null 244 */ ofNanos(long nanos)245 public static Duration ofNanos(long nanos) { 246 long secs = nanos / NANOS_PER_SECOND; 247 int nos = (int) (nanos % NANOS_PER_SECOND); 248 if (nos < 0) { 249 nos += NANOS_PER_SECOND; 250 secs--; 251 } 252 return create(secs, nos); 253 } 254 255 //----------------------------------------------------------------------- 256 /** 257 * Obtains an instance of {@code Duration} from a duration in the specified unit. 258 * <p> 259 * The parameters represent the two parts of a phrase like '6 Hours'. For example: 260 * <pre> 261 * Duration.of(3, SECONDS); 262 * Duration.of(465, HOURS); 263 * </pre> 264 * Only a subset of units are accepted by this method. 265 * The unit must either have an {@link TemporalUnit#isDurationEstimated() exact duration} or 266 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 267 * 268 * @param amount the amount of the duration, measured in terms of the unit, positive or negative 269 * @param unit the unit that the duration is measured in, must have an exact duration, not null 270 * @return a {@code Duration}, not null 271 * @throws DateTimeException if the period unit has an estimated duration 272 * @throws ArithmeticException if a numeric overflow occurs 273 */ of(long amount, TemporalUnit unit)274 public static Duration of(long amount, TemporalUnit unit) { 275 return ZERO.plus(amount, unit); 276 } 277 278 //----------------------------------------------------------------------- 279 /** 280 * Obtains an instance of {@code Duration} from an amount. 281 * <p> 282 * This obtains a duration based on the specified amount. 283 * A TemporalAmount represents an amount of time, which may be date-based 284 * or time-based, which this factory extracts to a duration. 285 * <p> 286 * The conversion loops around the set of units from the amount and uses 287 * the duration of the unit to calculate the total Duration. 288 * Only a subset of units are accepted by this method. 289 * The unit must either have an exact duration or be ChronoUnit.DAYS which 290 * is treated as 24 hours. If any other units are found then an exception is thrown. 291 * 292 * @param amount the amount to convert, not null 293 * @return a {@code Duration}, not null 294 * @throws DateTimeException if the amount cannot be converted 295 * @throws ArithmeticException if a numeric overflow occurs 296 */ from(TemporalAmount amount)297 public static Duration from(TemporalAmount amount) { 298 Jdk8Methods.requireNonNull(amount, "amount"); 299 Duration duration = ZERO; 300 for (TemporalUnit unit : amount.getUnits()) { 301 duration = duration.plus(amount.get(unit), unit); 302 } 303 return duration; 304 } 305 306 //----------------------------------------------------------------------- 307 /** 308 * Obtains an instance of {@code Duration} representing the duration between two instants. 309 * <p> 310 * Obtains a {@code Duration} representing the duration between two instants. 311 * This calculates the duration between two temporal objects of the same type. 312 * The difference in seconds is calculated using {@link Temporal#until(Temporal, TemporalUnit)}. 313 * The difference in nanoseconds is calculated using by querying the 314 * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field. 315 * <p> 316 * The result of this method can be a negative period if the end is before the start. 317 * To guarantee to obtain a positive duration call abs() on the result. 318 * 319 * @param startInclusive the start instant, inclusive, not null 320 * @param endExclusive the end instant, exclusive, not null 321 * @return a {@code Duration}, not null 322 * @throws DateTimeException if the seconds between the temporals cannot be obtained 323 * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} 324 */ between(Temporal startInclusive, Temporal endExclusive)325 public static Duration between(Temporal startInclusive, Temporal endExclusive) { 326 long secs = startInclusive.until(endExclusive, SECONDS); 327 long nanos = 0; 328 if (startInclusive.isSupported(NANO_OF_SECOND) && endExclusive.isSupported(NANO_OF_SECOND)) { 329 try { 330 long startNos = startInclusive.getLong(NANO_OF_SECOND); 331 nanos = endExclusive.getLong(NANO_OF_SECOND) - startNos; 332 if (secs > 0 && nanos < 0) { 333 nanos += NANOS_PER_SECOND; 334 } else if (secs < 0 && nanos > 0) { 335 nanos -= NANOS_PER_SECOND; 336 } else if (secs == 0 && nanos != 0) { 337 // two possible meanings for result, so recalculate secs 338 Temporal adjustedEnd = endExclusive.with(NANO_OF_SECOND, startNos); 339 secs = startInclusive.until(adjustedEnd, SECONDS);; 340 } 341 } catch (DateTimeException ex2) { 342 // ignore and only use seconds 343 } catch (ArithmeticException ex2) { 344 // ignore and only use seconds 345 } 346 } 347 return ofSeconds(secs, nanos); 348 } 349 350 //----------------------------------------------------------------------- 351 /** 352 * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}. 353 * <p> 354 * This will parse a textual representation of a duration, including the 355 * string produced by {@code toString()}. The formats accepted are based 356 * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days 357 * considered to be exactly 24 hours. 358 * <p> 359 * The string starts with an optional sign, denoted by the ASCII negative 360 * or positive symbol. If negative, the whole period is negated. 361 * The ASCII letter "P" is next in upper or lower case. 362 * There are then four sections, each consisting of a number and a suffix. 363 * The sections have suffixes in ASCII of "D", "H", "M" and "S" for 364 * days, hours, minutes and seconds, accepted in upper or lower case. 365 * The suffixes must occur in order. The ASCII letter "T" must occur before 366 * the first occurrence, if any, of an hour, minute or second section. 367 * At least one of the four sections must be present, and if "T" is present 368 * there must be at least one section after the "T". 369 * The number part of each section must consist of one or more ASCII digits. 370 * The number may be prefixed by the ASCII negative or positive symbol. 371 * The number of days, hours and minutes must parse to a {@code long}. 372 * The number of seconds must parse to a {@code long} with optional fraction. 373 * The decimal point may be either a dot or a comma. 374 * The fractional part may have from zero to 9 digits. 375 * <p> 376 * The leading plus/minus sign, and negative values for other units are 377 * not part of the ISO-8601 standard. 378 * <p> 379 * Examples: 380 * <pre> 381 * "PT20.345S" -> parses as "20.345 seconds" 382 * "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds) 383 * "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds) 384 * "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds) 385 * "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes" 386 * "P-6H3M" -> parses as "-6 hours and +3 minutes" 387 * "-P6H3M" -> parses as "-6 hours and -3 minutes" 388 * "-P-6H+3M" -> parses as "+6 hours and -3 minutes" 389 * </pre> 390 * 391 * @param text the text to parse, not null 392 * @return the parsed duration, not null 393 * @throws DateTimeParseException if the text cannot be parsed to a duration 394 */ parse(CharSequence text)395 public static Duration parse(CharSequence text) { 396 Jdk8Methods.requireNonNull(text, "text"); 397 Matcher matcher = PATTERN.matcher(text); 398 if (matcher.matches()) { 399 // check for letter T but no time sections 400 if ("T".equals(matcher.group(3)) == false) { 401 boolean negate = "-".equals(matcher.group(1)); 402 String dayMatch = matcher.group(2); 403 String hourMatch = matcher.group(4); 404 String minuteMatch = matcher.group(5); 405 String secondMatch = matcher.group(6); 406 String fractionMatch = matcher.group(7); 407 if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { 408 long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); 409 long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); 410 long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); 411 long seconds = parseNumber(text, secondMatch, 1, "seconds"); 412 boolean negativeSecs = secondMatch != null && secondMatch.charAt(0) == '-'; 413 int nanos = parseFraction(text, fractionMatch, negativeSecs ? -1 : 1); 414 try { 415 return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); 416 } catch (ArithmeticException ex) { 417 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex); 418 } 419 } 420 } 421 } 422 throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); 423 } 424 parseNumber(CharSequence text, String parsed, int multiplier, String errorText)425 private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { 426 // regex limits to [-+]?[0-9]+ 427 if (parsed == null) { 428 return 0; 429 } 430 try { 431 if (parsed.startsWith("+")) { 432 parsed = parsed.substring(1); 433 } 434 long val = Long.parseLong(parsed); 435 return Jdk8Methods.safeMultiply(val, multiplier); 436 } catch (NumberFormatException ex) { 437 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); 438 } catch (ArithmeticException ex) { 439 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); 440 } 441 } 442 parseFraction(CharSequence text, String parsed, int negate)443 private static int parseFraction(CharSequence text, String parsed, int negate) { 444 // regex limits to [0-9]{0,9} 445 if (parsed == null || parsed.length() == 0) { 446 return 0; 447 } 448 try { 449 parsed = (parsed + "000000000").substring(0, 9); 450 return Integer.parseInt(parsed) * negate; 451 } catch (NumberFormatException ex) { 452 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); 453 } catch (ArithmeticException ex) { 454 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); 455 } 456 } 457 create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos)458 private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) { 459 long seconds = Jdk8Methods.safeAdd(daysAsSecs, Jdk8Methods.safeAdd(hoursAsSecs, Jdk8Methods.safeAdd(minsAsSecs, secs))); 460 if (negate) { 461 return ofSeconds(seconds, nanos).negated(); 462 } 463 return ofSeconds(seconds, nanos); 464 } 465 466 //----------------------------------------------------------------------- 467 /** 468 * Obtains an instance of {@code Duration} using seconds and nanoseconds. 469 * 470 * @param seconds the length of the duration in seconds, positive or negative 471 * @param nanoAdjustment the nanosecond adjustment within the second, from 0 to 999,999,999 472 */ create(long seconds, int nanoAdjustment)473 private static Duration create(long seconds, int nanoAdjustment) { 474 if ((seconds | nanoAdjustment) == 0) { 475 return ZERO; 476 } 477 return new Duration(seconds, nanoAdjustment); 478 } 479 480 /** 481 * Constructs an instance of {@code Duration} using seconds and nanoseconds. 482 * 483 * @param seconds the length of the duration in seconds, positive or negative 484 * @param nanos the nanoseconds within the second, from 0 to 999,999,999 485 */ Duration(long seconds, int nanos)486 private Duration(long seconds, int nanos) { 487 super(); 488 this.seconds = seconds; 489 this.nanos = nanos; 490 } 491 492 //----------------------------------------------------------------------- 493 @Override getUnits()494 public List<TemporalUnit> getUnits() { 495 return Collections.<TemporalUnit>unmodifiableList(Arrays.asList(SECONDS, NANOS)); 496 } 497 498 @Override get(TemporalUnit unit)499 public long get(TemporalUnit unit) { 500 if (unit == SECONDS) { 501 return seconds; 502 } 503 if (unit == NANOS) { 504 return nanos; 505 } 506 throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); 507 } 508 509 //----------------------------------------------------------------------- 510 /** 511 * Checks if this duration is zero length. 512 * <p> 513 * A {@code Duration} represents a directed distance between two points on 514 * the time-line and can therefore be positive, zero or negative. 515 * This method checks whether the length is zero. 516 * 517 * @return true if this duration has a total length equal to zero 518 */ isZero()519 public boolean isZero() { 520 return (seconds | nanos) == 0; 521 } 522 523 /** 524 * Checks if this duration is negative, excluding zero. 525 * <p> 526 * A {@code Duration} represents a directed distance between two points on 527 * the time-line and can therefore be positive, zero or negative. 528 * This method checks whether the length is less than zero. 529 * 530 * @return true if this duration has a total length less than zero 531 */ isNegative()532 public boolean isNegative() { 533 return seconds < 0; 534 } 535 536 //----------------------------------------------------------------------- 537 /** 538 * Gets the number of seconds in this duration. 539 * <p> 540 * The length of the duration is stored using two fields - seconds and nanoseconds. 541 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 542 * the length in seconds. 543 * The total duration is defined by calling this method and {@link #getNano()}. 544 * <p> 545 * A {@code Duration} represents a directed distance between two points on the time-line. 546 * A negative duration is expressed by the negative sign of the seconds part. 547 * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds. 548 * 549 * @return the whole seconds part of the length of the duration, positive or negative 550 */ getSeconds()551 public long getSeconds() { 552 return seconds; 553 } 554 555 /** 556 * Gets the number of nanoseconds within the second in this duration. 557 * <p> 558 * The length of the duration is stored using two fields - seconds and nanoseconds. 559 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 560 * the length in seconds. 561 * The total duration is defined by calling this method and {@link #getSeconds()}. 562 * <p> 563 * A {@code Duration} represents a directed distance between two points on the time-line. 564 * A negative duration is expressed by the negative sign of the seconds part. 565 * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds. 566 * 567 * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999 568 */ getNano()569 public int getNano() { 570 return nanos; 571 } 572 573 //----------------------------------------------------------------------- 574 /** 575 * Returns a copy of this duration with the specified amount of seconds. 576 * <p> 577 * This returns a duration with the specified seconds, retaining the 578 * nano-of-second part of this duration. 579 * <p> 580 * This instance is immutable and unaffected by this method call. 581 * 582 * @param seconds the seconds to represent, may be negative 583 * @return a {@code Duration} based on this period with the requested seconds, not null 584 */ withSeconds(long seconds)585 public Duration withSeconds(long seconds) { 586 return create(seconds, nanos); 587 } 588 589 /** 590 * Returns a copy of this duration with the specified nano-of-second. 591 * <p> 592 * This returns a duration with the specified nano-of-second, retaining the 593 * seconds part of this duration. 594 * <p> 595 * This instance is immutable and unaffected by this method call. 596 * 597 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 598 * @return a {@code Duration} based on this period with the requested nano-of-second, not null 599 * @throws DateTimeException if the nano-of-second is invalid 600 */ withNanos(int nanoOfSecond)601 public Duration withNanos(int nanoOfSecond) { 602 NANO_OF_SECOND.checkValidIntValue(nanoOfSecond); 603 return create(seconds, nanoOfSecond); 604 } 605 606 //----------------------------------------------------------------------- 607 /** 608 * Returns a copy of this duration with the specified duration added. 609 * <p> 610 * This instance is immutable and unaffected by this method call. 611 * 612 * @param duration the duration to add, positive or negative, not null 613 * @return a {@code Duration} based on this duration with the specified duration added, not null 614 * @throws ArithmeticException if numeric overflow occurs 615 */ plus(Duration duration)616 public Duration plus(Duration duration) { 617 return plus(duration.getSeconds(), duration.getNano()); 618 } 619 620 /** 621 * Returns a copy of this duration with the specified duration added. 622 * <p> 623 * The duration amount is measured in terms of the specified unit. 624 * Only a subset of units are accepted by this method. 625 * The unit must either have an {@link TemporalUnit#isDurationEstimated() exact duration} or 626 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 627 * <p> 628 * This instance is immutable and unaffected by this method call. 629 * 630 * @param amountToAdd the amount of the period, measured in terms of the unit, positive or negative 631 * @param unit the unit that the period is measured in, must have an exact duration, not null 632 * @return a {@code Duration} based on this duration with the specified duration added, not null 633 * @throws ArithmeticException if numeric overflow occurs 634 */ plus(long amountToAdd, TemporalUnit unit)635 public Duration plus(long amountToAdd, TemporalUnit unit) { 636 Jdk8Methods.requireNonNull(unit, "unit"); 637 if (unit == DAYS) { 638 return plus(Jdk8Methods.safeMultiply(amountToAdd, SECONDS_PER_DAY), 0); 639 } 640 if (unit.isDurationEstimated()) { 641 throw new DateTimeException("Unit must not have an estimated duration"); 642 } 643 if (amountToAdd == 0) { 644 return this; 645 } 646 if (unit instanceof ChronoUnit) { 647 switch ((ChronoUnit) unit) { 648 case NANOS: return plusNanos(amountToAdd); 649 case MICROS: return plusSeconds((amountToAdd / (1000000L * 1000)) * 1000).plusNanos((amountToAdd % (1000000L * 1000)) * 1000); 650 case MILLIS: return plusMillis(amountToAdd); 651 case SECONDS: return plusSeconds(amountToAdd); 652 } 653 return plusSeconds(Jdk8Methods.safeMultiply(unit.getDuration().seconds, amountToAdd)); 654 } 655 Duration duration = unit.getDuration().multipliedBy(amountToAdd); 656 return plusSeconds(duration.getSeconds()).plusNanos(duration.getNano()); 657 } 658 659 //----------------------------------------------------------------------- 660 /** 661 * Returns a copy of this duration with the specified duration in 24 hour days added. 662 * <p> 663 * This instance is immutable and unaffected by this method call. 664 * 665 * @param daysToAdd the days to add, positive or negative 666 * @return a {@code Duration} based on this duration with the specified days added, not null 667 * @throws ArithmeticException if numeric overflow occurs 668 */ plusDays(long daysToAdd)669 public Duration plusDays(long daysToAdd) { 670 return plus(Jdk8Methods.safeMultiply(daysToAdd, SECONDS_PER_DAY), 0); 671 } 672 673 /** 674 * Returns a copy of this duration with the specified duration in hours added. 675 * <p> 676 * This instance is immutable and unaffected by this method call. 677 * 678 * @param hoursToAdd the hours to add, positive or negative 679 * @return a {@code Duration} based on this duration with the specified hours added, not null 680 * @throws ArithmeticException if numeric overflow occurs 681 */ plusHours(long hoursToAdd)682 public Duration plusHours(long hoursToAdd) { 683 return plus(Jdk8Methods.safeMultiply(hoursToAdd, SECONDS_PER_HOUR), 0); 684 } 685 686 /** 687 * Returns a copy of this duration with the specified duration in minutes added. 688 * <p> 689 * This instance is immutable and unaffected by this method call. 690 * 691 * @param minutesToAdd the minutes to add, positive or negative 692 * @return a {@code Duration} based on this duration with the specified minutes added, not null 693 * @throws ArithmeticException if numeric overflow occurs 694 */ plusMinutes(long minutesToAdd)695 public Duration plusMinutes(long minutesToAdd) { 696 return plus(Jdk8Methods.safeMultiply(minutesToAdd, SECONDS_PER_MINUTE), 0); 697 } 698 699 /** 700 * Returns a copy of this duration with the specified duration in seconds added. 701 * <p> 702 * This instance is immutable and unaffected by this method call. 703 * 704 * @param secondsToAdd the seconds to add, positive or negative 705 * @return a {@code Duration} based on this duration with the specified seconds added, not null 706 * @throws ArithmeticException if numeric overflow occurs 707 */ plusSeconds(long secondsToAdd)708 public Duration plusSeconds(long secondsToAdd) { 709 return plus(secondsToAdd, 0); 710 } 711 712 /** 713 * Returns a copy of this duration with the specified duration in milliseconds added. 714 * <p> 715 * This instance is immutable and unaffected by this method call. 716 * 717 * @param millisToAdd the milliseconds to add, positive or negative 718 * @return a {@code Duration} based on this duration with the specified milliseconds added, not null 719 * @throws ArithmeticException if numeric overflow occurs 720 */ plusMillis(long millisToAdd)721 public Duration plusMillis(long millisToAdd) { 722 return plus(millisToAdd / 1000, (millisToAdd % 1000) * NANOS_PER_MILLI); 723 } 724 725 /** 726 * Returns a copy of this duration with the specified duration in nanoseconds added. 727 * <p> 728 * This instance is immutable and unaffected by this method call. 729 * 730 * @param nanosToAdd the nanoseconds to add, positive or negative 731 * @return a {@code Duration} based on this duration with the specified nanoseconds added, not null 732 * @throws ArithmeticException if numeric overflow occurs 733 */ plusNanos(long nanosToAdd)734 public Duration plusNanos(long nanosToAdd) { 735 return plus(0, nanosToAdd); 736 } 737 738 /** 739 * Returns a copy of this duration with the specified duration added. 740 * <p> 741 * This instance is immutable and unaffected by this method call. 742 * 743 * @param secondsToAdd the seconds to add, positive or negative 744 * @param nanosToAdd the nanos to add, positive or negative 745 * @return a {@code Duration} based on this duration with the specified seconds added, not null 746 * @throws ArithmeticException if numeric overflow occurs 747 */ plus(long secondsToAdd, long nanosToAdd)748 private Duration plus(long secondsToAdd, long nanosToAdd) { 749 if ((secondsToAdd | nanosToAdd) == 0) { 750 return this; 751 } 752 long epochSec = Jdk8Methods.safeAdd(seconds, secondsToAdd); 753 epochSec = Jdk8Methods.safeAdd(epochSec, nanosToAdd / NANOS_PER_SECOND); 754 nanosToAdd = nanosToAdd % NANOS_PER_SECOND; 755 long nanoAdjustment = nanos + nanosToAdd; // safe int+NANOS_PER_SECOND 756 return ofSeconds(epochSec, nanoAdjustment); 757 } 758 759 //----------------------------------------------------------------------- 760 /** 761 * Returns a copy of this duration with the specified duration subtracted. 762 * <p> 763 * This instance is immutable and unaffected by this method call. 764 * 765 * @param duration the duration to subtract, positive or negative, not null 766 * @return a {@code Duration} based on this duration with the specified duration subtracted, not null 767 * @throws ArithmeticException if numeric overflow occurs 768 */ minus(Duration duration)769 public Duration minus(Duration duration) { 770 long secsToSubtract = duration.getSeconds(); 771 int nanosToSubtract = duration.getNano(); 772 if (secsToSubtract == Long.MIN_VALUE) { 773 return plus(Long.MAX_VALUE, -nanosToSubtract).plus(1, 0); 774 } 775 return plus(-secsToSubtract, -nanosToSubtract); 776 } 777 778 /** 779 * Returns a copy of this duration with the specified duration subtracted. 780 * <p> 781 * The duration amount is measured in terms of the specified unit. 782 * Only a subset of units are accepted by this method. 783 * The unit must either have an {@link TemporalUnit#isDurationEstimated() exact duration} or 784 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 785 * <p> 786 * This instance is immutable and unaffected by this method call. 787 * 788 * @param amountToSubtract the amount of the period, measured in terms of the unit, positive or negative 789 * @param unit the unit that the period is measured in, must have an exact duration, not null 790 * @return a {@code Duration} based on this duration with the specified duration subtracted, not null 791 * @throws ArithmeticException if numeric overflow occurs 792 */ minus(long amountToSubtract, TemporalUnit unit)793 public Duration minus(long amountToSubtract, TemporalUnit unit) { 794 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); 795 } 796 797 //----------------------------------------------------------------------- 798 /** 799 * Returns a copy of this duration with the specified duration in 24 hour days subtracted. 800 * <p> 801 * This instance is immutable and unaffected by this method call. 802 * 803 * @param daysToSubtract the days to subtract, positive or negative 804 * @return a {@code Duration} based on this duration with the specified days subtracted, not null 805 * @throws ArithmeticException if numeric overflow occurs 806 */ minusDays(long daysToSubtract)807 public Duration minusDays(long daysToSubtract) { 808 return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); 809 } 810 811 /** 812 * Returns a copy of this duration with the specified duration in hours subtracted. 813 * <p> 814 * This instance is immutable and unaffected by this method call. 815 * 816 * @param hoursToSubtract the hours to subtract, positive or negative 817 * @return a {@code Duration} based on this duration with the specified hours subtracted, not null 818 * @throws ArithmeticException if numeric overflow occurs 819 */ minusHours(long hoursToSubtract)820 public Duration minusHours(long hoursToSubtract) { 821 return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); 822 } 823 824 /** 825 * Returns a copy of this duration with the specified duration in minutes subtracted. 826 * <p> 827 * This instance is immutable and unaffected by this method call. 828 * 829 * @param minutesToSubtract the minutes to subtract, positive or negative 830 * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null 831 * @throws ArithmeticException if numeric overflow occurs 832 */ minusMinutes(long minutesToSubtract)833 public Duration minusMinutes(long minutesToSubtract) { 834 return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); 835 } 836 837 /** 838 * Returns a copy of this duration with the specified duration in seconds subtracted. 839 * <p> 840 * This instance is immutable and unaffected by this method call. 841 * 842 * @param secondsToSubtract the seconds to subtract, positive or negative 843 * @return a {@code Duration} based on this duration with the specified seconds subtracted, not null 844 * @throws ArithmeticException if numeric overflow occurs 845 */ minusSeconds(long secondsToSubtract)846 public Duration minusSeconds(long secondsToSubtract) { 847 return (secondsToSubtract == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-secondsToSubtract)); 848 } 849 850 /** 851 * Returns a copy of this duration with the specified duration in milliseconds subtracted. 852 * <p> 853 * This instance is immutable and unaffected by this method call. 854 * 855 * @param millisToSubtract the milliseconds to subtract, positive or negative 856 * @return a {@code Duration} based on this duration with the specified milliseconds subtracted, not null 857 * @throws ArithmeticException if numeric overflow occurs 858 */ minusMillis(long millisToSubtract)859 public Duration minusMillis(long millisToSubtract) { 860 return (millisToSubtract == Long.MIN_VALUE ? plusMillis(Long.MAX_VALUE).plusMillis(1) : plusMillis(-millisToSubtract)); 861 } 862 863 /** 864 * Returns a copy of this duration with the specified duration in nanoseconds subtracted. 865 * <p> 866 * This instance is immutable and unaffected by this method call. 867 * 868 * @param nanosToSubtract the nanoseconds to subtract, positive or negative 869 * @return a {@code Duration} based on this duration with the specified nanoseconds subtracted, not null 870 * @throws ArithmeticException if numeric overflow occurs 871 */ minusNanos(long nanosToSubtract)872 public Duration minusNanos(long nanosToSubtract) { 873 return (nanosToSubtract == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanosToSubtract)); 874 } 875 876 //----------------------------------------------------------------------- 877 /** 878 * Returns a copy of this duration multiplied by the scalar. 879 * <p> 880 * This instance is immutable and unaffected by this method call. 881 * 882 * @param multiplicand the value to multiply the duration by, positive or negative 883 * @return a {@code Duration} based on this duration multiplied by the specified scalar, not null 884 * @throws ArithmeticException if numeric overflow occurs 885 */ multipliedBy(long multiplicand)886 public Duration multipliedBy(long multiplicand) { 887 if (multiplicand == 0) { 888 return ZERO; 889 } 890 if (multiplicand == 1) { 891 return this; 892 } 893 return create(toSeconds().multiply(BigDecimal.valueOf(multiplicand))); 894 } 895 896 /** 897 * Returns a copy of this duration divided by the specified value. 898 * <p> 899 * This instance is immutable and unaffected by this method call. 900 * 901 * @param divisor the value to divide the duration by, positive or negative, not zero 902 * @return a {@code Duration} based on this duration divided by the specified divisor, not null 903 * @throws ArithmeticException if the divisor is zero 904 * @throws ArithmeticException if numeric overflow occurs 905 */ dividedBy(long divisor)906 public Duration dividedBy(long divisor) { 907 if (divisor == 0) { 908 throw new ArithmeticException("Cannot divide by zero"); 909 } 910 if (divisor == 1) { 911 return this; 912 } 913 return create(toSeconds().divide(BigDecimal.valueOf(divisor), RoundingMode.DOWN)); 914 } 915 916 /** 917 * Converts this duration to the total length in seconds and 918 * fractional nanoseconds expressed as a {@code BigDecimal}. 919 * 920 * @return the total length of the duration in seconds, with a scale of 9, not null 921 */ toSeconds()922 private BigDecimal toSeconds() { 923 return BigDecimal.valueOf(seconds).add(BigDecimal.valueOf(nanos, 9)); 924 } 925 926 /** 927 * Creates an instance of {@code Duration} from a number of seconds. 928 * 929 * @param seconds the number of seconds, up to scale 9, positive or negative 930 * @return a {@code Duration}, not null 931 * @throws ArithmeticException if numeric overflow occurs 932 */ create(BigDecimal seconds)933 private static Duration create(BigDecimal seconds) { 934 BigInteger nanos = seconds.movePointRight(9).toBigIntegerExact(); 935 BigInteger[] divRem = nanos.divideAndRemainder(BI_NANOS_PER_SECOND); 936 if (divRem[0].bitLength() > 63) { 937 throw new ArithmeticException("Exceeds capacity of Duration: " + nanos); 938 } 939 return ofSeconds(divRem[0].longValue(), divRem[1].intValue()); 940 } 941 942 //----------------------------------------------------------------------- 943 /** 944 * Returns a copy of this duration with the length negated. 945 * <p> 946 * This method swaps the sign of the total length of this duration. 947 * For example, {@code PT1.3S} will be returned as {@code PT-1.3S}. 948 * <p> 949 * This instance is immutable and unaffected by this method call. 950 * 951 * @return a {@code Duration} based on this duration with the amount negated, not null 952 * @throws ArithmeticException if numeric overflow occurs 953 */ negated()954 public Duration negated() { 955 return multipliedBy(-1); 956 } 957 958 /** 959 * Returns a copy of this duration with a positive length. 960 * <p> 961 * This method returns a positive duration by effectively removing the sign from any negative total length. 962 * For example, {@code PT-1.3S} will be returned as {@code PT1.3S}. 963 * <p> 964 * This instance is immutable and unaffected by this method call. 965 * 966 * @return a {@code Duration} based on this duration with an absolute length, not null 967 * @throws ArithmeticException if numeric overflow occurs 968 */ abs()969 public Duration abs() { 970 return isNegative() ? negated() : this; 971 } 972 973 //------------------------------------------------------------------------- 974 /** 975 * Adds this duration to the specified temporal object. 976 * <p> 977 * This returns a temporal object of the same observable type as the input 978 * with this duration added. 979 * <p> 980 * In most cases, it is clearer to reverse the calling pattern by using 981 * {@link Temporal#plus(TemporalAmount)}. 982 * <pre> 983 * // these two lines are equivalent, but the second approach is recommended 984 * dateTime = thisDuration.addTo(dateTime); 985 * dateTime = dateTime.plus(thisDuration); 986 * </pre> 987 * <p> 988 * The calculation will add the seconds, then nanos. 989 * Only non-zero amounts will be added. 990 * <p> 991 * This instance is immutable and unaffected by this method call. 992 * 993 * @param temporal the temporal object to adjust, not null 994 * @return an object of the same type with the adjustment made, not null 995 * @throws DateTimeException if unable to add 996 * @throws ArithmeticException if numeric overflow occurs 997 */ 998 @Override addTo(Temporal temporal)999 public Temporal addTo(Temporal temporal) { 1000 if (seconds != 0) { 1001 temporal = temporal.plus(seconds, SECONDS); 1002 } 1003 if (nanos != 0) { 1004 temporal = temporal.plus(nanos, NANOS); 1005 } 1006 return temporal; 1007 } 1008 1009 /** 1010 * Subtracts this duration from the specified temporal object. 1011 * <p> 1012 * This returns a temporal object of the same observable type as the input 1013 * with this duration subtracted. 1014 * <p> 1015 * In most cases, it is clearer to reverse the calling pattern by using 1016 * {@link Temporal#minus(TemporalAmount)}. 1017 * <pre> 1018 * // these two lines are equivalent, but the second approach is recommended 1019 * dateTime = thisDuration.subtractFrom(dateTime); 1020 * dateTime = dateTime.minus(thisDuration); 1021 * </pre> 1022 * <p> 1023 * The calculation will subtract the seconds, then nanos. 1024 * Only non-zero amounts will be added. 1025 * <p> 1026 * This instance is immutable and unaffected by this method call. 1027 * 1028 * @param temporal the temporal object to adjust, not null 1029 * @return an object of the same type with the adjustment made, not null 1030 * @throws DateTimeException if unable to subtract 1031 * @throws ArithmeticException if numeric overflow occurs 1032 */ 1033 @Override subtractFrom(Temporal temporal)1034 public Temporal subtractFrom(Temporal temporal) { 1035 if (seconds != 0) { 1036 temporal = temporal.minus(seconds, SECONDS); 1037 } 1038 if (nanos != 0) { 1039 temporal = temporal.minus(nanos, NANOS); 1040 } 1041 return temporal; 1042 } 1043 1044 //----------------------------------------------------------------------- 1045 /** 1046 * Gets the number of days in this duration. 1047 * <p> 1048 * This returns the total number of days in the duration by dividing the 1049 * number of seconds by 86400. 1050 * This is based on the standard definition of a day as 24 hours. 1051 * <p> 1052 * This instance is immutable and unaffected by this method call. 1053 * 1054 * @return the number of days in the duration, may be negative 1055 */ toDays()1056 public long toDays() { 1057 return seconds / SECONDS_PER_DAY; 1058 } 1059 1060 /** 1061 * Gets the number of hours in this duration. 1062 * <p> 1063 * This returns the total number of hours in the duration by dividing the 1064 * number of seconds by 3600. 1065 * <p> 1066 * This instance is immutable and unaffected by this method call. 1067 * 1068 * @return the number of hours in the duration, may be negative 1069 */ toHours()1070 public long toHours() { 1071 return seconds / SECONDS_PER_HOUR; 1072 } 1073 1074 /** 1075 * Gets the number of minutes in this duration. 1076 * <p> 1077 * This returns the total number of minutes in the duration by dividing the 1078 * number of seconds by 60. 1079 * <p> 1080 * This instance is immutable and unaffected by this method call. 1081 * 1082 * @return the number of minutes in the duration, may be negative 1083 */ toMinutes()1084 public long toMinutes() { 1085 return seconds / SECONDS_PER_MINUTE; 1086 } 1087 1088 /** 1089 * Converts this duration to the total length in milliseconds. 1090 * <p> 1091 * If this duration is too large to fit in a {@code long} milliseconds, then an 1092 * exception is thrown. 1093 * <p> 1094 * If this duration has greater than millisecond precision, then the conversion 1095 * will drop any excess precision information as though the amount in nanoseconds 1096 * was subject to integer division by one million. 1097 * 1098 * @return the total length of the duration in milliseconds 1099 * @throws ArithmeticException if numeric overflow occurs 1100 */ toMillis()1101 public long toMillis() { 1102 long result = Jdk8Methods.safeMultiply(seconds, 1000); 1103 result = Jdk8Methods.safeAdd(result, nanos / NANOS_PER_MILLI); 1104 return result; 1105 } 1106 1107 /** 1108 * Converts this duration to the total length in nanoseconds expressed as a {@code long}. 1109 * <p> 1110 * If this duration is too large to fit in a {@code long} nanoseconds, then an 1111 * exception is thrown. 1112 * 1113 * @return the total length of the duration in nanoseconds 1114 * @throws ArithmeticException if numeric overflow occurs 1115 */ toNanos()1116 public long toNanos() { 1117 long result = Jdk8Methods.safeMultiply(seconds, NANOS_PER_SECOND); 1118 result = Jdk8Methods.safeAdd(result, nanos); 1119 return result; 1120 } 1121 1122 //----------------------------------------------------------------------- work in progress 1123 /** 1124 * Extracts the number of days in this duration. 1125 * <p> 1126 * This returns the total number of days in the duration by dividing the number of seconds by 86400. 1127 * This is based on the standard definition of a day as 24 hours. 1128 * <p> 1129 * This instance is immutable and unaffected by this method call. 1130 * 1131 * @return the number of days in the duration, may be negative 1132 * @since 1.5.0 (only added in Java 9) 1133 */ toDaysPart()1134 public long toDaysPart() { 1135 return seconds / SECONDS_PER_DAY; 1136 } 1137 1138 /** 1139 * Extracts the number of hours part in this duration. 1140 * <p> 1141 * This returns the number of remaining hours when dividing {@link Duration#toHours()} by hours in a day. 1142 * This is based on the standard definition of a day as 24 hours. 1143 * <p> 1144 * This instance is immutable and unaffected by this method call. 1145 * 1146 * @return the number of hours part in the duration, may be negative 1147 * @since 1.5.0 (only added in Java 9) 1148 */ toHoursPart()1149 public int toHoursPart() { 1150 return (int) (toHours() % LocalTime.HOURS_PER_DAY); 1151 } 1152 1153 /** 1154 * Extracts the number of minutes part in this duration. 1155 * <p> 1156 * This returns the number of remaining minutes when dividing {@link Duration#toMinutes()} by minutes in an hour. 1157 * This is based on the standard definition of an hour as 60 minutes. 1158 * <p> 1159 * This instance is immutable and by this method call. 1160 * 1161 * @return the number of minutes parts in the duration, may be negative 1162 * @since 1.5.0 (only added in Java 9) 1163 */ toMinutesPart()1164 public int toMinutesPart() { 1165 return (int) (toMinutes() % LocalTime.MINUTES_PER_HOUR); 1166 } 1167 1168 /** 1169 * Extracts the number of seconds part in this duration. 1170 * <p> 1171 * This returns the remaining seconds when dividing {@link Duration#toSeconds} by seconds in a minute. 1172 * This is based on the standard definition of a minute as 60 seconds. 1173 * <p> 1174 * This instance is immutable and unaffected by this method call. 1175 * 1176 * @return the number of seconds parts in the duration, may be negative 1177 * @since 1.5.0 (only added in Java 9) 1178 */ toSecondsPart()1179 public int toSecondsPart() { 1180 return (int) (seconds % SECONDS_PER_MINUTE); 1181 } 1182 1183 /** 1184 * Extracts the number of milliseconds part of this duration. 1185 * <p> 1186 * This returns the milliseconds part by dividing the number of nanoseconds by 1,000,000. 1187 * The length of the duration is stored using two fields - seconds and nanoseconds. 1188 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to the length in seconds. 1189 * The total duration is defined by calling {@link Duration#getNano()} and {@link Duration#getSeconds()}. 1190 * <p> 1191 * This instance is immutable and unaffected by this method call. 1192 * 1193 * @return the number of milliseconds part of the duration. 1194 * @since 1.5.0 (only added in Java 9) 1195 */ toMillisPart()1196 public int toMillisPart() { 1197 return nanos / NANOS_PER_MILLI; 1198 } 1199 1200 /** 1201 * Get the nanoseconds part within seconds of the duration. 1202 * <p> 1203 * The length of the duration is stored using two fields - seconds and nanoseconds. 1204 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to the length in seconds. 1205 * The total duration is defined by calling {@link Duration#getNano()} and {@link Duration#getSeconds()}. 1206 * <p> 1207 * This instance is immutable and unaffected by this method call. 1208 * 1209 * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999 1210 * @since 1.5.0 (only added in Java 9) 1211 */ toNanosPart()1212 public int toNanosPart() { 1213 return nanos; 1214 } 1215 1216 //----------------------------------------------------------------------- 1217 /** 1218 * Compares this duration to the specified {@code Duration}. 1219 * <p> 1220 * The comparison is based on the total length of the durations. 1221 * It is "consistent with equals", as defined by {@link Comparable}. 1222 * 1223 * @param otherDuration the other duration to compare to, not null 1224 * @return the comparator value, negative if less, positive if greater 1225 */ 1226 @Override compareTo(Duration otherDuration)1227 public int compareTo(Duration otherDuration) { 1228 int cmp = Jdk8Methods.compareLongs(seconds, otherDuration.seconds); 1229 if (cmp != 0) { 1230 return cmp; 1231 } 1232 return nanos - otherDuration.nanos; 1233 } 1234 1235 //----------------------------------------------------------------------- 1236 /** 1237 * Checks if this duration is equal to the specified {@code Duration}. 1238 * <p> 1239 * The comparison is based on the total length of the durations. 1240 * 1241 * @param otherDuration the other duration, null returns false 1242 * @return true if the other duration is equal to this one 1243 */ 1244 @Override equals(Object otherDuration)1245 public boolean equals(Object otherDuration) { 1246 if (this == otherDuration) { 1247 return true; 1248 } 1249 if (otherDuration instanceof Duration) { 1250 Duration other = (Duration) otherDuration; 1251 return this.seconds == other.seconds && 1252 this.nanos == other.nanos; 1253 } 1254 return false; 1255 } 1256 1257 /** 1258 * A hash code for this duration. 1259 * 1260 * @return a suitable hash code 1261 */ 1262 @Override hashCode()1263 public int hashCode() { 1264 return ((int) (seconds ^ (seconds >>> 32))) + (51 * nanos); 1265 } 1266 1267 //----------------------------------------------------------------------- 1268 /** 1269 * A string representation of this duration using ISO-8601 seconds 1270 * based representation, such as {@code PT8H6M12.345S}. 1271 * <p> 1272 * The format of the returned string will be {@code PTnHnMnS}, where n is 1273 * the relevant hours, minutes or seconds part of the duration. 1274 * Any fractional seconds are placed after a decimal point i the seconds section. 1275 * If a section has a zero value, it is omitted. 1276 * The hours, minutes and seconds will all have the same sign. 1277 * <p> 1278 * Examples: 1279 * <pre> 1280 * "20.345 seconds" -> "PT20.345S 1281 * "15 minutes" (15 * 60 seconds) -> "PT15M" 1282 * "10 hours" (10 * 3600 seconds) -> "PT10H" 1283 * "2 days" (2 * 86400 seconds) -> "PT48H" 1284 * </pre> 1285 * Note that multiples of 24 hours are not output as days to avoid confusion 1286 * with {@code Period}. 1287 * 1288 * @return an ISO-8601 representation of this duration, not null 1289 */ 1290 @Override toString()1291 public String toString() { 1292 if (this == ZERO) { 1293 return "PT0S"; 1294 } 1295 long hours = seconds / SECONDS_PER_HOUR; 1296 int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); 1297 int secs = (int) (seconds % SECONDS_PER_MINUTE); 1298 StringBuilder buf = new StringBuilder(24); 1299 buf.append("PT"); 1300 if (hours != 0) { 1301 buf.append(hours).append('H'); 1302 } 1303 if (minutes != 0) { 1304 buf.append(minutes).append('M'); 1305 } 1306 if (secs == 0 && nanos == 0 && buf.length() > 2) { 1307 return buf.toString(); 1308 } 1309 if (secs < 0 && nanos > 0) { 1310 if (secs == -1) { 1311 buf.append("-0"); 1312 } else { 1313 buf.append(secs + 1); 1314 } 1315 } else { 1316 buf.append(secs); 1317 } 1318 if (nanos > 0) { 1319 int pos = buf.length(); 1320 if (secs < 0) { 1321 buf.append(2 * NANOS_PER_SECOND - nanos); 1322 } else { 1323 buf.append(nanos + NANOS_PER_SECOND); 1324 } 1325 while (buf.charAt(buf.length() - 1) == '0') { 1326 buf.setLength(buf.length() - 1); 1327 } 1328 buf.setCharAt(pos, '.'); 1329 } 1330 buf.append('S'); 1331 return buf.toString(); 1332 } 1333 1334 //----------------------------------------------------------------------- writeReplace()1335 private Object writeReplace() { 1336 return new Ser(Ser.DURATION_TYPE, this); 1337 } 1338 1339 /** 1340 * Defend against malicious streams. 1341 * @return never 1342 * @throws InvalidObjectException always 1343 */ readResolve()1344 private Object readResolve() throws ObjectStreamException { 1345 throw new InvalidObjectException("Deserialization via serialization delegate"); 1346 } 1347 writeExternal(DataOutput out)1348 void writeExternal(DataOutput out) throws IOException { 1349 out.writeLong(seconds); 1350 out.writeInt(nanos); 1351 } 1352 readExternal(DataInput in)1353 static Duration readExternal(DataInput in) throws IOException { 1354 long seconds = in.readLong(); 1355 int nanos = in.readInt(); 1356 return Duration.ofSeconds(seconds, nanos); 1357 } 1358 1359 } 1360