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