1 /* 2 * hunt-time: A time library for D programming language. 3 * 4 * Copyright (C) 2015-2018 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.time.Duration; 13 14 import hunt.time.Constants; 15 import hunt.time.Ser; 16 17 import hunt.stream.DataInput; 18 import hunt.stream.DataOutput; 19 import hunt.Exceptions; 20 // //import hunt.io.ObjectInputStream; 21 import hunt.stream.Common; 22 import hunt.math.BigDecimal; 23 import hunt.math.BigInteger; 24 import hunt.time.Exceptions; 25 import hunt.time.format.DateTimeParseException; 26 import hunt.time.temporal.ChronoField; 27 import hunt.time.temporal.ChronoUnit; 28 import hunt.time.temporal.Temporal; 29 import hunt.time.temporal.TemporalAmount; 30 import hunt.time.temporal.TemporalUnit; 31 import hunt.time.Exceptions; 32 import hunt.time.util.Common; 33 34 import hunt.collection; 35 import hunt.Functions; 36 import hunt.Long; 37 import hunt.math.Helper; 38 import hunt.text.Common; 39 import hunt.util.StringBuilder; 40 import hunt.util.Common; 41 import hunt.util.Comparator; 42 // import hunt.serialization.JsonSerializer; 43 44 import std.conv; 45 import std.concurrency : initOnce; 46 import std.regex; 47 import std.string; 48 49 /** 50 * A time-based amount of time, such as '34.5 seconds'. 51 * !(p) 52 * This class models a quantity or amount of time _in terms of seconds and nanoseconds. 53 * It can be accessed using other duration-based units, such as minutes and hours. 54 * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as 55 * exactly equal to 24 hours, thus ignoring daylight savings effects. 56 * See {@link Period} for the date-based equivalent to this class. 57 * !(p) 58 * A physical duration could be of infinite length. 59 * For practicality, the duration is stored with constraints similar to {@link Instant}. 60 * The duration uses nanosecond resolution with a maximum value of the seconds that can 61 * be held _in a {@code long}. This is greater than the current estimated age of the universe. 62 * !(p) 63 * The range of a duration requires the storage of a number larger than a {@code long}. 64 * To achieve this, the class stores a {@code long} representing seconds and an {@code int} 65 * representing nanosecond-of-second, which will always be between 0 and 999,999,999. 66 * The model is of a directed duration, meaning that the duration may be negative. 67 * !(p) 68 * The duration is measured _in "seconds", but these are not necessarily identical to 69 * the scientific "SI second" definition based on atomic clocks. 70 * This difference only impacts durations measured near a leap-second and should not affect 71 * most applications. 72 * See {@link Instant} for a discussion as to the meaning of the second and time-scales. 73 * 74 * !(p) 75 * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> 76 * class; use of identity-sensitive operations (including reference equality 77 * ({@code ==}), identity hash code, or synchronization) on instances of 78 * {@code Duration} may have unpredictable results and should be avoided. 79 * The {@code equals} method should be used for comparisons. 80 * 81 * @implSpec 82 * This class is immutable and thread-safe. 83 * 84 * @since 1.8 85 */ 86 final class Duration 87 : TemporalAmount, Comparable!(Duration) { // , Serializable 88 89 /** 90 * Constant for a duration of zero. 91 */ 92 static Duration ZERO() { 93 __gshared Duration _ZERO; 94 return initOnce!(_ZERO)(new Duration(0, 0)); 95 } 96 97 /** 98 * Constant for nanos per second. 99 */ 100 // __gshared BigInteger BI_NANOS_PER_SECOND; 101 static BigInteger BI_NANOS_PER_SECOND() { 102 __gshared BigInteger _v; 103 return initOnce!(_v)(BigInteger.valueOf(TimeConstant.NANOS_PER_SECOND)); 104 } 105 106 /** 107 * The pattern for parsing. 108 */ 109 enum string PATTERN = 110 "([-+]?)P(?:([-+]?[0-9]+)D)?" ~ 111 "(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?"; 112 /** 113 * The number of seconds _in the duration. 114 */ 115 private long seconds; 116 /** 117 * The number of nanoseconds _in the duration, expressed as a fraction of the 118 * number of seconds. This is always positive, and never exceeds 999,999,999. 119 */ 120 private int nanos; 121 122 //----------------------------------------------------------------------- 123 /** 124 * Obtains a {@code Duration} representing a number of standard 24 hour days. 125 * !(p) 126 * The seconds are calculated based on the standard definition of a day, 127 * where each day is 86400 seconds which implies a 24 hour day. 128 * The nanosecond _in second field is set to zero. 129 * 130 * @param days the number of days, positive or negative 131 * @return a {@code Duration}, not null 132 * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} 133 */ 134 static Duration ofDays(long days) { 135 return create(MathHelper.multiplyExact(days , TimeConstant.SECONDS_PER_DAY), 0); 136 } 137 138 /** 139 * Obtains a {@code Duration} representing a number of standard hours. 140 * !(p) 141 * The seconds are calculated based on the standard definition of an hour, 142 * where each hour is 3600 seconds. 143 * The nanosecond _in second field is set to zero. 144 * 145 * @param hours the number of hours, positive or negative 146 * @return a {@code Duration}, not null 147 * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} 148 */ 149 static Duration ofHours(long hours) { 150 return create(MathHelper.multiplyExact(hours, TimeConstant.SECONDS_PER_HOUR), 0); 151 } 152 153 /** 154 * Obtains a {@code Duration} representing a number of standard minutes. 155 * !(p) 156 * The seconds are calculated based on the standard definition of a minute, 157 * where each minute is 60 seconds. 158 * The nanosecond _in second field is set to zero. 159 * 160 * @param minutes the number of minutes, positive or negative 161 * @return a {@code Duration}, not null 162 * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} 163 */ 164 static Duration ofMinutes(long minutes) { 165 return create(MathHelper.multiplyExact(minutes, TimeConstant.SECONDS_PER_MINUTE), 0); 166 } 167 168 //----------------------------------------------------------------------- 169 /** 170 * Obtains a {@code Duration} representing a number of seconds. 171 * !(p) 172 * The nanosecond _in second field is set to zero. 173 * 174 * @param seconds the number of seconds, positive or negative 175 * @return a {@code Duration}, not null 176 */ 177 static Duration ofSeconds(long seconds) { 178 return create(seconds, 0); 179 } 180 181 /** 182 * Obtains a {@code Duration} representing a number of seconds and an 183 * adjustment _in nanoseconds. 184 * !(p) 185 * This method allows an arbitrary number of nanoseconds to be passed _in. 186 * The factory will alter the values of the second and nanosecond _in order 187 * to ensure that the stored nanosecond is _in the range 0 to 999,999,999. 188 * For example, the following will result _in exactly the same duration: 189 * !(pre) 190 * Duration.ofSeconds(3, 1); 191 * Duration.ofSeconds(4, -999_999_999); 192 * Duration.ofSeconds(2, 1000_000_001); 193 * </pre> 194 * 195 * @param seconds the number of seconds, positive or negative 196 * @param nanoAdjustment the nanosecond adjustment to the number of seconds, positive or negative 197 * @return a {@code Duration}, not null 198 * @throws ArithmeticException if the adjustment causes the seconds to exceed the capacity of {@code Duration} 199 */ 200 static Duration ofSeconds(long seconds, long nanoAdjustment) { 201 long secs = MathHelper.addExact(seconds , MathHelper.floorDiv(nanoAdjustment , TimeConstant.NANOS_PER_SECOND)); 202 int nos = cast(int) (MathHelper.floorMod(nanoAdjustment, TimeConstant.NANOS_PER_SECOND)); 203 return create(secs, nos); 204 } 205 206 //----------------------------------------------------------------------- 207 /** 208 * Obtains a {@code Duration} representing a number of milliseconds. 209 * !(p) 210 * The seconds and nanoseconds are extracted from the specified milliseconds. 211 * 212 * @param millis the number of milliseconds, positive or negative 213 * @return a {@code Duration}, not null 214 */ 215 static Duration ofMillis(long millis) { 216 long secs = millis / 1000; 217 int mos = cast(int) (millis % 1000); 218 if (mos < 0) { 219 mos += 1000; 220 secs--; 221 } 222 return create(secs, mos * 1000_000); 223 } 224 225 //----------------------------------------------------------------------- 226 /** 227 * Obtains a {@code Duration} representing a number of nanoseconds. 228 * !(p) 229 * The seconds and nanoseconds are extracted from the specified nanoseconds. 230 * 231 * @param nanos the number of nanoseconds, positive or negative 232 * @return a {@code Duration}, not null 233 */ 234 static Duration ofNanos(long nanos) { 235 long secs = nanos / TimeConstant.NANOS_PER_SECOND; 236 int nos = cast(int) (nanos % TimeConstant.NANOS_PER_SECOND); 237 if (nos < 0) { 238 nos += TimeConstant.NANOS_PER_SECOND; 239 secs--; 240 } 241 return create(secs, nos); 242 } 243 244 //----------------------------------------------------------------------- 245 /** 246 * Obtains a {@code Duration} representing an amount _in the specified unit. 247 * !(p) 248 * The parameters represent the two parts of a phrase like '6 Hours'. For example: 249 * !(pre) 250 * Duration.of(3, SECONDS); 251 * Duration.of(465, HOURS); 252 * </pre> 253 * Only a subset of units are accepted by this method. 254 * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or 255 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 256 * 257 * @param amount the amount of the duration, measured _in terms of the unit, positive or negative 258 * @param unit the unit that the duration is measured _in, must have an exact duration, not null 259 * @return a {@code Duration}, not null 260 * @throws DateTimeException if the period unit has an estimated duration 261 * @throws ArithmeticException if a numeric overflow occurs 262 */ 263 static Duration of(long amount, TemporalUnit unit) { 264 return ZERO.plus(amount, unit); 265 } 266 267 //----------------------------------------------------------------------- 268 /** 269 * Obtains an instance of {@code Duration} from a temporal amount. 270 * !(p) 271 * This obtains a duration based on the specified amount. 272 * A {@code TemporalAmount} represents an amount of time, which may be 273 * date-based or time-based, which this factory extracts to a duration. 274 * !(p) 275 * The conversion loops around the set of units from the amount and uses 276 * the {@linkplain TemporalUnit#getDuration() duration} of the unit to 277 * calculate the total {@code Duration}. 278 * Only a subset of units are accepted by this method. The unit must either 279 * have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} 280 * or be {@link ChronoUnit#DAYS} which is treated as 24 hours. 281 * If any other units are found then an exception is thrown. 282 * 283 * @param amount the temporal amount to convert, not null 284 * @return the equivalent duration, not null 285 * @throws DateTimeException if unable to convert to a {@code Duration} 286 * @throws ArithmeticException if numeric overflow occurs 287 */ 288 static Duration from(TemporalAmount amount) { 289 assert(amount, "amount"); 290 Duration duration = ZERO; 291 foreach(TemporalUnit unit ; amount.getUnits()) { 292 duration = duration.plus(amount.get(unit), unit); 293 } 294 return duration; 295 } 296 297 //----------------------------------------------------------------------- 298 /** 299 * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}. 300 * !(p) 301 * This will parse a textual representation of a duration, including the 302 * string produced by {@code toString()}. The formats accepted are based 303 * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days 304 * considered to be exactly 24 hours. 305 * !(p) 306 * The string starts with an optional sign, denoted by the ASCII negative 307 * or positive symbol. If negative, the whole period is negated. 308 * The ASCII letter "P" is next _in upper or lower case. 309 * There are then four sections, each consisting of a number and a suffix. 310 * The sections have suffixes _in ASCII of "D", "H", "M" and "S" for 311 * days, hours, minutes and seconds, accepted _in upper or lower case. 312 * The suffixes must occur _in order. The ASCII letter "T" must occur before 313 * the first occurrence, if any, of an hour, minute or second section. 314 * At least one of the four sections must be present, and if "T" is present 315 * there must be at least one section after the "T". 316 * The number part of each section must consist of one or more ASCII digits. 317 * The number may be prefixed by the ASCII negative or positive symbol. 318 * The number of days, hours and minutes must parse to a {@code long}. 319 * The number of seconds must parse to a {@code long} with optional fraction. 320 * The decimal point may be either a dot or a comma. 321 * The fractional part may have from zero to 9 digits. 322 * !(p) 323 * The leading plus/minus sign, and negative values for other units are 324 * not part of the ISO-8601 standard. 325 * !(p) 326 * Examples: 327 * !(pre) 328 * "PT20.345S" -- parses as "20.345 seconds" 329 * "PT15M" -- parses as "15 minutes" (where a minute is 60 seconds) 330 * "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds) 331 * "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds) 332 * "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes" 333 * "PT-6H3M" -- parses as "-6 hours and +3 minutes" 334 * "-PT6H3M" -- parses as "-6 hours and -3 minutes" 335 * "-PT-6H+3M" -- parses as "+6 hours and -3 minutes" 336 * </pre> 337 * 338 * @param text the text to parse, not null 339 * @return the parsed duration, not null 340 * @throws DateTimeParseException if the text cannot be parsed to a duration 341 */ 342 static Duration parse(string text) { 343 assert(text, "text"); 344 auto matchers = matchAll(text, PATTERN); 345 if (!matchers.empty()) { 346 // check for letter T but no time sections 347 auto matcher = matchers.front(); 348 if (!charMatch(text, matcher.captures[2], 'T')) { 349 bool negate = charMatch(text, matcher.captures[0], '-'); 350 351 string dayStart = matcher.captures[1]; 352 string hourStart = matcher.captures[3]; 353 string minuteStart = matcher.captures[4]; 354 string secondStart = matcher.captures[5]; 355 string fractionStart = matcher.captures[6]; 356 357 if (dayStart.length >= 0 || hourStart.length >= 0 || minuteStart.length >= 0 || secondStart.length >= 0) { 358 long daysAsSecs = parseNumber(text, dayStart, TimeConstant.SECONDS_PER_DAY, "days"); 359 long hoursAsSecs = parseNumber(text, hourStart, TimeConstant.SECONDS_PER_HOUR, "hours"); 360 long minsAsSecs = parseNumber(text, minuteStart, TimeConstant.SECONDS_PER_MINUTE, "minutes"); 361 long seconds = parseNumber(text, secondStart, 1, "seconds"); 362 bool negativeSecs = secondStart.length >= 0 && secondStart[0] == '-'; 363 int nanos = parseFraction(text, fractionStart, negativeSecs ? -1 : 1); 364 try { 365 return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); 366 } catch (ArithmeticException ex) { 367 throw cast(DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0)/* .initCause(ex) */; 368 } 369 } 370 } 371 } 372 throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); 373 } 374 375 private static bool charMatch(string text, string m, char c) { 376 return (m.length == 1 && m[0] == c); 377 } 378 379 private static long parseNumber(string text, string data, int multiplier, string errorText) { 380 // regex limits to [-+]?[0-9]+ 381 if (!isNumeric(data) || data.length == 0) { 382 return 0; 383 } 384 try { 385 long val = to!long(data); 386 return MathHelper.multiplyExact(val , multiplier); 387 } catch (Exception ex) { 388 throw new Exception("Text cannot be parsed to a Duration: " ~ ex.msg); 389 } 390 } 391 392 private static int parseFraction(string text, string data, int negate) { 393 // regex limits to [0-9]{0,9} 394 if (!isNumeric(data) || data.length == 0) { 395 return 0; 396 } 397 try { 398 int fraction = to!int(data); 399 400 // for number strings smaller than 9 digits, interpret as if there 401 // were trailing zeros 402 for (int i = cast(int)(data.length); i < 9; i++) { 403 fraction *= 10; 404 } 405 return fraction * negate; 406 } catch (Exception ex) { 407 throw new Exception("Text cannot be parsed to a Duration: fraction , " ,ex.msg); 408 } 409 } 410 411 private static Duration create(bool negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) { 412 long seconds = MathHelper.addExact(daysAsSecs , MathHelper.addExact(hoursAsSecs , MathHelper.addExact(minsAsSecs , secs))); 413 if (negate) { 414 return ofSeconds(seconds, nanos).negated(); 415 } 416 return ofSeconds(seconds, nanos); 417 } 418 419 //----------------------------------------------------------------------- 420 /** 421 * Obtains a {@code Duration} representing the duration between two temporal objects. 422 * !(p) 423 * This calculates the duration between two temporal objects. If the objects 424 * are of different types, then the duration is calculated based on the type 425 * of the first object. For example, if the first argument is a {@code TimeConstant} 426 * then the second argument is converted to a {@code TimeConstant}. 427 * !(p) 428 * The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit. 429 * For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the 430 * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported. 431 * !(p) 432 * The result of this method can be a negative period if the end is before the start. 433 * To guarantee to obtain a positive duration call {@link #abs()} on the result. 434 * 435 * @param startInclusive the start instant, inclusive, not null 436 * @param endExclusive the end instant, exclusive, not null 437 * @return a {@code Duration}, not null 438 * @throws DateTimeException if the seconds between the temporals cannot be obtained 439 * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} 440 */ 441 static Duration between(Temporal startInclusive, Temporal endExclusive) { 442 try { 443 return ofNanos(startInclusive.until(endExclusive, ChronoUnit.NANOS)); 444 } catch (DateTimeException ex) { 445 long secs = startInclusive.until(endExclusive, ChronoUnit.SECONDS); 446 long nanos; 447 try { 448 nanos = endExclusive.getLong(ChronoField.NANO_OF_SECOND) - startInclusive.getLong(ChronoField.NANO_OF_SECOND); 449 if (secs > 0 && nanos < 0) { 450 secs++; 451 } else if (secs < 0 && nanos > 0) { 452 secs--; 453 } 454 } catch (DateTimeException ex2) { 455 nanos = 0; 456 } 457 return ofSeconds(secs, nanos); 458 } 459 } 460 461 //----------------------------------------------------------------------- 462 /** 463 * Obtains an instance of {@code Duration} using seconds and nanoseconds. 464 * 465 * @param seconds the length of the duration _in seconds, positive or negative 466 * @param nanoAdjustment the nanosecond adjustment within the second, from 0 to 999,999,999 467 */ 468 private static Duration create(long seconds, int nanoAdjustment) { 469 if ((seconds | nanoAdjustment) == 0) { 470 return ZERO; 471 } 472 return new Duration(seconds, nanoAdjustment); 473 } 474 475 /** 476 * Constructs an instance of {@code Duration} using seconds and nanoseconds. 477 * 478 * @param seconds the length of the duration _in seconds, positive or negative 479 * @param nanos the nanoseconds within the second, from 0 to 999,999,999 480 */ 481 this(long seconds, int nanos) { 482 // super();///@gxc 483 this.seconds = seconds; 484 this.nanos = nanos; 485 } 486 487 //----------------------------------------------------------------------- 488 /** 489 * Gets the value of the requested unit. 490 * !(p) 491 * This returns a value for each of the two supported units, 492 * {@link ChronoUnit#SECONDS SECONDS} and {@link ChronoUnit#NANOS NANOS}. 493 * All other units throw an exception. 494 * 495 * @param unit the {@code TemporalUnit} for which to return the value 496 * @return the long value of the unit 497 * @throws DateTimeException if the unit is not supported 498 * @throws UnsupportedTemporalTypeException if the unit is not supported 499 */ 500 override 501 long get(TemporalUnit unit) { 502 if (unit == ChronoUnit.SECONDS) { 503 return seconds; 504 } else if (unit == ChronoUnit.NANOS) { 505 return nanos; 506 } else { 507 throw new UnsupportedTemporalTypeException("Unsupported unit: " ~ typeid(unit).stringof); 508 } 509 } 510 511 /** 512 * Gets the set of units supported by this duration. 513 * !(p) 514 * The supported units are {@link ChronoUnit#SECONDS SECONDS}, 515 * and {@link ChronoUnit#NANOS NANOS}. 516 * They are returned _in the order seconds, nanos. 517 * !(p) 518 * This set can be used _in conjunction with {@link #get(TemporalUnit)} 519 * to access the entire state of the duration. 520 * 521 * @return a list containing the seconds and nanos units, not null 522 */ 523 override 524 List!(TemporalUnit) getUnits() { 525 __gshared List!(TemporalUnit) _UNITS; 526 return initOnce!(_UNITS)({ 527 auto r = new ArrayList!(TemporalUnit)(); 528 r.add(ChronoUnit.SECONDS); 529 r.add(ChronoUnit.NANOS); 530 return r; 531 }()); 532 } 533 534 535 //----------------------------------------------------------------------- 536 /** 537 * Checks if this duration is zero length. 538 * !(p) 539 * A {@code Duration} represents a directed distance between two points on 540 * the time-line and can therefore be positive, zero or negative. 541 * This method checks whether the length is zero. 542 * 543 * @return true if this duration has a total length equal to zero 544 */ 545 bool isZero() { 546 return (seconds | nanos) == 0; 547 } 548 549 /** 550 * Checks if this duration is negative, excluding zero. 551 * !(p) 552 * A {@code Duration} represents a directed distance between two points on 553 * the time-line and can therefore be positive, zero or negative. 554 * This method checks whether the length is less than zero. 555 * 556 * @return true if this duration has a total length less than zero 557 */ 558 bool isNegative() { 559 return seconds < 0; 560 } 561 562 //----------------------------------------------------------------------- 563 /** 564 * Gets the number of seconds _in this duration. 565 * !(p) 566 * The length of the duration is stored using two fields - seconds and nanoseconds. 567 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 568 * the length _in seconds. 569 * The total duration is defined by calling this method and {@link #getNano()}. 570 * !(p) 571 * A {@code Duration} represents a directed distance between two points on the time-line. 572 * A negative duration is expressed by the negative sign of the seconds part. 573 * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds. 574 * 575 * @return the whole seconds part of the length of the duration, positive or negative 576 */ 577 long getSeconds() { 578 return seconds; 579 } 580 581 /** 582 * Gets the number of nanoseconds within the second _in this duration. 583 * !(p) 584 * The length of the duration is stored using two fields - seconds and nanoseconds. 585 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 586 * the length _in seconds. 587 * The total duration is defined by calling this method and {@link #getSeconds()}. 588 * !(p) 589 * A {@code Duration} represents a directed distance between two points on the time-line. 590 * A negative duration is expressed by the negative sign of the seconds part. 591 * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds. 592 * 593 * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999 594 */ 595 int getNano() { 596 return nanos; 597 } 598 599 //----------------------------------------------------------------------- 600 /** 601 * Returns a copy of this duration with the specified amount of seconds. 602 * !(p) 603 * This returns a duration with the specified seconds, retaining the 604 * nano-of-second part of this duration. 605 * !(p) 606 * This instance is immutable and unaffected by this method call. 607 * 608 * @param seconds the seconds to represent, may be negative 609 * @return a {@code Duration} based on this period with the requested seconds, not null 610 */ 611 Duration withSeconds(long seconds) { 612 return create(seconds, nanos); 613 } 614 615 /** 616 * Returns a copy of this duration with the specified nano-of-second. 617 * !(p) 618 * This returns a duration with the specified nano-of-second, retaining the 619 * seconds part of this duration. 620 * !(p) 621 * This instance is immutable and unaffected by this method call. 622 * 623 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 624 * @return a {@code Duration} based on this period with the requested nano-of-second, not null 625 * @throws DateTimeException if the nano-of-second is invalid 626 */ 627 Duration withNanos(int nanoOfSecond) { 628 ChronoField.NANO_OF_SECOND.checkValidIntValue(nanoOfSecond); 629 return create(seconds, nanoOfSecond); 630 } 631 632 //----------------------------------------------------------------------- 633 /** 634 * Returns a copy of this duration with the specified duration added. 635 * !(p) 636 * This instance is immutable and unaffected by this method call. 637 * 638 * @param duration the duration to add, positive or negative, 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 Duration plus(Duration duration) { 643 return plus(duration.getSeconds(), duration.getNano()); 644 } 645 646 /** 647 * Returns a copy of this duration with the specified duration added. 648 * !(p) 649 * The duration amount is measured _in terms of the specified unit. 650 * Only a subset of units are accepted by this method. 651 * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or 652 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 653 * !(p) 654 * This instance is immutable and unaffected by this method call. 655 * 656 * @param amountToAdd the amount to add, measured _in terms of the unit, positive or negative 657 * @param unit the unit that the amount is measured _in, must have an exact duration, not null 658 * @return a {@code Duration} based on this duration with the specified duration added, not null 659 * @throws UnsupportedTemporalTypeException if the unit is not supported 660 * @throws ArithmeticException if numeric overflow occurs 661 */ 662 Duration plus(long amountToAdd, TemporalUnit unit) { 663 assert(unit, "unit"); 664 if (unit == ChronoUnit.DAYS) { 665 return plus(MathHelper.multiplyExact(amountToAdd , TimeConstant.SECONDS_PER_DAY), 0); 666 } 667 if (unit.isDurationEstimated()) { 668 throw new UnsupportedTemporalTypeException("Unit must not have an estimated duration"); 669 } 670 if (amountToAdd == 0) { 671 return this; 672 } 673 if (cast(ChronoUnit)(unit) !is null) { 674 { 675 if ((cast(ChronoUnit) unit).toString == ChronoUnit.NANOS.toString) return plusNanos(amountToAdd); 676 if ((cast(ChronoUnit) unit).toString == ChronoUnit.MICROS.toString) return plusSeconds((amountToAdd / (1000_000L * 1000)) * 1000).plusNanos((amountToAdd % (1000_000L * 1000)) * 1000); 677 if ((cast(ChronoUnit) unit).toString == ChronoUnit.MILLIS.toString) return plusMillis(amountToAdd); 678 if ((cast(ChronoUnit) unit).toString == ChronoUnit.SECONDS.toString ) return plusSeconds(amountToAdd); 679 } 680 return plusSeconds(MathHelper.multiplyExact(unit.getDuration().seconds , amountToAdd)); 681 } 682 Duration duration = unit.getDuration().multipliedBy(amountToAdd); 683 return plusSeconds(duration.getSeconds()).plusNanos(duration.getNano()); 684 } 685 686 //----------------------------------------------------------------------- 687 /** 688 * Returns a copy of this duration with the specified duration _in standard 24 hour days added. 689 * !(p) 690 * The number of days is multiplied by 86400 to obtain the number of seconds to add. 691 * This is based on the standard definition of a day as 24 hours. 692 * !(p) 693 * This instance is immutable and unaffected by this method call. 694 * 695 * @param daysToAdd the days to add, positive or negative 696 * @return a {@code Duration} based on this duration with the specified days added, not null 697 * @throws ArithmeticException if numeric overflow occurs 698 */ 699 Duration plusDays(long daysToAdd) { 700 return plus(MathHelper.multiplyExact(daysToAdd , TimeConstant.SECONDS_PER_DAY), 0); 701 } 702 703 /** 704 * Returns a copy of this duration with the specified duration _in hours added. 705 * !(p) 706 * This instance is immutable and unaffected by this method call. 707 * 708 * @param hoursToAdd the hours to add, positive or negative 709 * @return a {@code Duration} based on this duration with the specified hours added, not null 710 * @throws ArithmeticException if numeric overflow occurs 711 */ 712 Duration plusHours(long hoursToAdd) { 713 return plus(MathHelper.multiplyExact(hoursToAdd , TimeConstant.SECONDS_PER_HOUR), 0); 714 } 715 716 /** 717 * Returns a copy of this duration with the specified duration _in minutes added. 718 * !(p) 719 * This instance is immutable and unaffected by this method call. 720 * 721 * @param minutesToAdd the minutes to add, positive or negative 722 * @return a {@code Duration} based on this duration with the specified minutes added, not null 723 * @throws ArithmeticException if numeric overflow occurs 724 */ 725 Duration plusMinutes(long minutesToAdd) { 726 return plus(MathHelper.multiplyExact(minutesToAdd , TimeConstant.SECONDS_PER_MINUTE), 0); 727 } 728 729 /** 730 * Returns a copy of this duration with the specified duration _in seconds added. 731 * !(p) 732 * This instance is immutable and unaffected by this method call. 733 * 734 * @param secondsToAdd the seconds to add, positive or negative 735 * @return a {@code Duration} based on this duration with the specified seconds added, not null 736 * @throws ArithmeticException if numeric overflow occurs 737 */ 738 Duration plusSeconds(long secondsToAdd) { 739 return plus(secondsToAdd, 0); 740 } 741 742 /** 743 * Returns a copy of this duration with the specified duration _in milliseconds added. 744 * !(p) 745 * This instance is immutable and unaffected by this method call. 746 * 747 * @param millisToAdd the milliseconds to add, positive or negative 748 * @return a {@code Duration} based on this duration with the specified milliseconds added, not null 749 * @throws ArithmeticException if numeric overflow occurs 750 */ 751 Duration plusMillis(long millisToAdd) { 752 return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000); 753 } 754 755 /** 756 * Returns a copy of this duration with the specified duration _in nanoseconds added. 757 * !(p) 758 * This instance is immutable and unaffected by this method call. 759 * 760 * @param nanosToAdd the nanoseconds to add, positive or negative 761 * @return a {@code Duration} based on this duration with the specified nanoseconds added, not null 762 * @throws ArithmeticException if numeric overflow occurs 763 */ 764 Duration plusNanos(long nanosToAdd) { 765 return plus(0, nanosToAdd); 766 } 767 768 /** 769 * Returns a copy of this duration with the specified duration added. 770 * !(p) 771 * This instance is immutable and unaffected by this method call. 772 * 773 * @param secondsToAdd the seconds to add, positive or negative 774 * @param nanosToAdd the nanos to add, positive or negative 775 * @return a {@code Duration} based on this duration with the specified seconds added, not null 776 * @throws ArithmeticException if numeric overflow occurs 777 */ 778 private Duration plus(long secondsToAdd, long nanosToAdd) { 779 if ((secondsToAdd | nanosToAdd) == 0) { 780 return this; 781 } 782 long epochSec = MathHelper.addExact(seconds , secondsToAdd); 783 epochSec = MathHelper.addExact(epochSec , nanosToAdd / TimeConstant.NANOS_PER_SECOND); 784 nanosToAdd = nanosToAdd % TimeConstant.NANOS_PER_SECOND; 785 long nanoAdjustment = nanos + nanosToAdd; // safe int+NANOS_PER_SECOND 786 return ofSeconds(epochSec, nanoAdjustment); 787 } 788 789 //----------------------------------------------------------------------- 790 /** 791 * Returns a copy of this duration with the specified duration subtracted. 792 * !(p) 793 * This instance is immutable and unaffected by this method call. 794 * 795 * @param duration the duration to subtract, positive or negative, not null 796 * @return a {@code Duration} based on this duration with the specified duration subtracted, not null 797 * @throws ArithmeticException if numeric overflow occurs 798 */ 799 Duration minus(Duration duration) { 800 long secsToSubtract = duration.getSeconds(); 801 int nanosToSubtract = duration.getNano(); 802 if (secsToSubtract == Long.MIN_VALUE) { 803 return plus(Long.MAX_VALUE, -nanosToSubtract).plus(1, 0); 804 } 805 return plus(-secsToSubtract, -nanosToSubtract); 806 } 807 808 /** 809 * Returns a copy of this duration with the specified duration subtracted. 810 * !(p) 811 * The duration amount is measured _in terms of the specified unit. 812 * Only a subset of units are accepted by this method. 813 * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or 814 * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception. 815 * !(p) 816 * This instance is immutable and unaffected by this method call. 817 * 818 * @param amountToSubtract the amount to subtract, measured _in terms of the unit, positive or negative 819 * @param unit the unit that the amount is measured _in, must have an exact duration, not null 820 * @return a {@code Duration} based on this duration with the specified duration subtracted, not null 821 * @throws ArithmeticException if numeric overflow occurs 822 */ 823 Duration minus(long amountToSubtract, TemporalUnit unit) { 824 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); 825 } 826 827 //----------------------------------------------------------------------- 828 /** 829 * Returns a copy of this duration with the specified duration _in standard 24 hour days subtracted. 830 * !(p) 831 * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. 832 * This is based on the standard definition of a day as 24 hours. 833 * !(p) 834 * This instance is immutable and unaffected by this method call. 835 * 836 * @param daysToSubtract the days to subtract, positive or negative 837 * @return a {@code Duration} based on this duration with the specified days subtracted, not null 838 * @throws ArithmeticException if numeric overflow occurs 839 */ 840 Duration minusDays(long daysToSubtract) { 841 return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); 842 } 843 844 /** 845 * Returns a copy of this duration with the specified duration _in hours subtracted. 846 * !(p) 847 * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. 848 * !(p) 849 * This instance is immutable and unaffected by this method call. 850 * 851 * @param hoursToSubtract the hours to subtract, positive or negative 852 * @return a {@code Duration} based on this duration with the specified hours subtracted, not null 853 * @throws ArithmeticException if numeric overflow occurs 854 */ 855 Duration minusHours(long hoursToSubtract) { 856 return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); 857 } 858 859 /** 860 * Returns a copy of this duration with the specified duration _in minutes subtracted. 861 * !(p) 862 * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. 863 * !(p) 864 * This instance is immutable and unaffected by this method call. 865 * 866 * @param minutesToSubtract the minutes to subtract, positive or negative 867 * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null 868 * @throws ArithmeticException if numeric overflow occurs 869 */ 870 Duration minusMinutes(long minutesToSubtract) { 871 return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); 872 } 873 874 /** 875 * Returns a copy of this duration with the specified duration _in seconds subtracted. 876 * !(p) 877 * This instance is immutable and unaffected by this method call. 878 * 879 * @param secondsToSubtract the seconds to subtract, positive or negative 880 * @return a {@code Duration} based on this duration with the specified seconds subtracted, not null 881 * @throws ArithmeticException if numeric overflow occurs 882 */ 883 Duration minusSeconds(long secondsToSubtract) { 884 return (secondsToSubtract == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-secondsToSubtract)); 885 } 886 887 /** 888 * Returns a copy of this duration with the specified duration _in milliseconds subtracted. 889 * !(p) 890 * This instance is immutable and unaffected by this method call. 891 * 892 * @param millisToSubtract the milliseconds to subtract, positive or negative 893 * @return a {@code Duration} based on this duration with the specified milliseconds subtracted, not null 894 * @throws ArithmeticException if numeric overflow occurs 895 */ 896 Duration minusMillis(long millisToSubtract) { 897 return (millisToSubtract == Long.MIN_VALUE ? plusMillis(Long.MAX_VALUE).plusMillis(1) : plusMillis(-millisToSubtract)); 898 } 899 900 /** 901 * Returns a copy of this duration with the specified duration _in nanoseconds subtracted. 902 * !(p) 903 * This instance is immutable and unaffected by this method call. 904 * 905 * @param nanosToSubtract the nanoseconds to subtract, positive or negative 906 * @return a {@code Duration} based on this duration with the specified nanoseconds subtracted, not null 907 * @throws ArithmeticException if numeric overflow occurs 908 */ 909 Duration minusNanos(long nanosToSubtract) { 910 return (nanosToSubtract == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanosToSubtract)); 911 } 912 913 //----------------------------------------------------------------------- 914 /** 915 * Returns a copy of this duration multiplied by the scalar. 916 * !(p) 917 * This instance is immutable and unaffected by this method call. 918 * 919 * @param multiplicand the value to multiply the duration by, positive or negative 920 * @return a {@code Duration} based on this duration multiplied by the specified scalar, not null 921 * @throws ArithmeticException if numeric overflow occurs 922 */ 923 Duration multipliedBy(long multiplicand) { 924 if (multiplicand == 0) { 925 return ZERO; 926 } 927 if (multiplicand == 1) { 928 return this; 929 } 930 return null /* create(toBigDecimalSeconds().multiply(BigDecimal.valueOf(multiplicand))) */; 931 } 932 933 /** 934 * Returns a copy of this duration divided by the specified value. 935 * !(p) 936 * This instance is immutable and unaffected by this method call. 937 * 938 * @param divisor the value to divide the duration by, positive or negative, not zero 939 * @return a {@code Duration} based on this duration divided by the specified divisor, not null 940 * @throws ArithmeticException if the divisor is zero or if numeric overflow occurs 941 */ 942 ///@gxc 943 // Duration dividedBy(long divisor) { 944 // if (divisor == 0) { 945 // throw new ArithmeticException("Cannot divide by zero"); 946 // } 947 // if (divisor == 1) { 948 // return this; 949 // } 950 // return create(toBigDecimalSeconds().divide(BigDecimal.valueOf(divisor), RoundingMode.DOWN.oldMode())); 951 // } 952 953 /** 954 * Returns number of whole times a specified Duration occurs within this Duration. 955 * !(p) 956 * This instance is immutable and unaffected by this method call. 957 * 958 * @param divisor the value to divide the duration by, positive or negative, not null 959 * @return number of whole times, rounded toward zero, a specified 960 * {@code Duration} occurs within this Duration, may be negative 961 * @throws ArithmeticException if the divisor is zero, or if numeric overflow occurs 962 * @since 9 963 */ 964 ///@gxc 965 // long dividedBy(Duration divisor) { 966 // assert(divisor, "divisor"); 967 // BigDecimal dividendBigD = toBigDecimalSeconds(); 968 // BigDecimal divisorBigD = divisor.toBigDecimalSeconds(); 969 // return dividendBigD.divideToIntegralValue(divisorBigD).longValueExact(); 970 // } 971 972 /** 973 * Converts this duration to the total length _in seconds and 974 * fractional nanoseconds expressed as a {@code BigDecimal}. 975 * 976 * @return the total length of the duration _in seconds, with a scale of 9, not null 977 */ 978 ///@gxc 979 // private BigDecimal toBigDecimalSeconds() { 980 // return BigDecimal.valueOf(seconds).add(BigDecimal.valueOf(nanos, 9)); 981 // } 982 983 /** 984 * Creates an instance of {@code Duration} from a number of seconds. 985 * 986 * @param seconds the number of seconds, up to scale 9, positive or negative 987 * @return a {@code Duration}, not null 988 * @throws ArithmeticException if numeric overflow occurs 989 */ 990 private static Duration create(BigDecimal seconds) { 991 BigInteger nanos = seconds.movePointRight(9).toBigIntegerExact(); 992 BigInteger[] divRem = nanos.divideAndRemainder(BI_NANOS_PER_SECOND); 993 if (divRem[0].bitLength() > 63) { 994 throw new ArithmeticException("Exceeds capacity of Duration: " ~ nanos.toString); 995 } 996 return ofSeconds(divRem[0].longValue(), divRem[1].intValue()); 997 } 998 999 //----------------------------------------------------------------------- 1000 /** 1001 * Returns a copy of this duration with the length negated. 1002 * !(p) 1003 * This method swaps the sign of the total length of this duration. 1004 * For example, {@code PT1.3S} will be returned as {@code PT-1.3S}. 1005 * !(p) 1006 * This instance is immutable and unaffected by this method call. 1007 * 1008 * @return a {@code Duration} based on this duration with the amount negated, not null 1009 * @throws ArithmeticException if numeric overflow occurs 1010 */ 1011 Duration negated() { 1012 return multipliedBy(-1); 1013 } 1014 1015 /** 1016 * Returns a copy of this duration with a positive length. 1017 * !(p) 1018 * This method returns a positive duration by effectively removing the sign from any negative total length. 1019 * For example, {@code PT-1.3S} will be returned as {@code PT1.3S}. 1020 * !(p) 1021 * This instance is immutable and unaffected by this method call. 1022 * 1023 * @return a {@code Duration} based on this duration with an absolute length, not null 1024 * @throws ArithmeticException if numeric overflow occurs 1025 */ 1026 Duration abs() { 1027 return isNegative() ? negated() : this; 1028 } 1029 1030 //------------------------------------------------------------------------- 1031 /** 1032 * Adds this duration to the specified temporal object. 1033 * !(p) 1034 * This returns a temporal object of the same observable type as the input 1035 * with this duration added. 1036 * !(p) 1037 * In most cases, it is clearer to reverse the calling pattern by using 1038 * {@link Temporal#plus(TemporalAmount)}. 1039 * !(pre) 1040 * // these two lines are equivalent, but the second approach is recommended 1041 * dateTime = thisDuration.addTo(dateTime); 1042 * dateTime = dateTime.plus(thisDuration); 1043 * </pre> 1044 * !(p) 1045 * The calculation will add the seconds, then nanos. 1046 * Only non-zero amounts will be added. 1047 * !(p) 1048 * This instance is immutable and unaffected by this method call. 1049 * 1050 * @param temporal the temporal object to adjust, not null 1051 * @return an object of the same type with the adjustment made, not null 1052 * @throws DateTimeException if unable to add 1053 * @throws ArithmeticException if numeric overflow occurs 1054 */ 1055 override 1056 Temporal addTo(Temporal temporal) { 1057 if (seconds != 0) { 1058 temporal = temporal.plus(seconds, ChronoUnit.SECONDS); 1059 } 1060 if (nanos != 0) { 1061 temporal = temporal.plus(nanos, ChronoUnit.NANOS); 1062 } 1063 return temporal; 1064 } 1065 1066 /** 1067 * Subtracts this duration from the specified temporal object. 1068 * !(p) 1069 * This returns a temporal object of the same observable type as the input 1070 * with this duration subtracted. 1071 * !(p) 1072 * In most cases, it is clearer to reverse the calling pattern by using 1073 * {@link Temporal#minus(TemporalAmount)}. 1074 * !(pre) 1075 * // these two lines are equivalent, but the second approach is recommended 1076 * dateTime = thisDuration.subtractFrom(dateTime); 1077 * dateTime = dateTime.minus(thisDuration); 1078 * </pre> 1079 * !(p) 1080 * The calculation will subtract the seconds, then nanos. 1081 * Only non-zero amounts will be added. 1082 * !(p) 1083 * This instance is immutable and unaffected by this method call. 1084 * 1085 * @param temporal the temporal object to adjust, not null 1086 * @return an object of the same type with the adjustment made, not null 1087 * @throws DateTimeException if unable to subtract 1088 * @throws ArithmeticException if numeric overflow occurs 1089 */ 1090 override 1091 Temporal subtractFrom(Temporal temporal) { 1092 if (seconds != 0) { 1093 temporal = temporal.minus(seconds, ChronoUnit.SECONDS); 1094 } 1095 if (nanos != 0) { 1096 temporal = temporal.minus(nanos, ChronoUnit.NANOS); 1097 } 1098 return temporal; 1099 } 1100 1101 //----------------------------------------------------------------------- 1102 /** 1103 * Gets the number of days _in this duration. 1104 * !(p) 1105 * This returns the total number of days _in the duration by dividing the 1106 * number of seconds by 86400. 1107 * This is based on the standard definition of a day as 24 hours. 1108 * !(p) 1109 * This instance is immutable and unaffected by this method call. 1110 * 1111 * @return the number of days _in the duration, may be negative 1112 */ 1113 long toDays() { 1114 return seconds / TimeConstant.SECONDS_PER_DAY; 1115 } 1116 1117 /** 1118 * Gets the number of hours _in this duration. 1119 * !(p) 1120 * This returns the total number of hours _in the duration by dividing the 1121 * number of seconds by 3600. 1122 * !(p) 1123 * This instance is immutable and unaffected by this method call. 1124 * 1125 * @return the number of hours _in the duration, may be negative 1126 */ 1127 long toHours() { 1128 return seconds / TimeConstant.SECONDS_PER_HOUR; 1129 } 1130 1131 /** 1132 * Gets the number of minutes _in this duration. 1133 * !(p) 1134 * This returns the total number of minutes _in the duration by dividing the 1135 * number of seconds by 60. 1136 * !(p) 1137 * This instance is immutable and unaffected by this method call. 1138 * 1139 * @return the number of minutes _in the duration, may be negative 1140 */ 1141 long toMinutes() { 1142 return seconds / TimeConstant.SECONDS_PER_MINUTE; 1143 } 1144 1145 /** 1146 * Gets the number of seconds _in this duration. 1147 * !(p) 1148 * This returns the total number of whole seconds _in the duration. 1149 * !(p) 1150 * This instance is immutable and unaffected by this method call. 1151 * 1152 * @return the whole seconds part of the length of the duration, positive or negative 1153 * @since 9 1154 */ 1155 long toSeconds() { 1156 return seconds; 1157 } 1158 1159 /** 1160 * Converts this duration to the total length _in milliseconds. 1161 * !(p) 1162 * If this duration is too large to fit _in a {@code long} milliseconds, then an 1163 * exception is thrown. 1164 * !(p) 1165 * If this duration has greater than millisecond precision, then the conversion 1166 * will drop any excess precision information as though the amount _in nanoseconds 1167 * was subject to integer division by one million. 1168 * 1169 * @return the total length of the duration _in milliseconds 1170 * @throws ArithmeticException if numeric overflow occurs 1171 */ 1172 long toMillis() { 1173 long tempSeconds = seconds; 1174 long tempNanos = nanos; 1175 if (tempSeconds < 0) { 1176 // change the seconds and nano value to 1177 // handle Long.MIN_VALUE case 1178 tempSeconds = tempSeconds + 1; 1179 tempNanos = tempNanos - TimeConstant.NANOS_PER_SECOND; 1180 } 1181 long millis = MathHelper.multiplyExact(tempSeconds , 1000); 1182 millis = MathHelper.addExact(millis, tempNanos / TimeConstant.NANOS_PER_MILLI); 1183 return millis; 1184 } 1185 1186 /** 1187 * Converts this duration to the total length _in nanoseconds expressed as a {@code long}. 1188 * !(p) 1189 * If this duration is too large to fit _in a {@code long} nanoseconds, then an 1190 * exception is thrown. 1191 * 1192 * @return the total length of the duration _in nanoseconds 1193 * @throws ArithmeticException if numeric overflow occurs 1194 */ 1195 long toNanos() { 1196 long tempSeconds = seconds; 1197 long tempNanos = nanos; 1198 if (tempSeconds < 0) { 1199 // change the seconds and nano value to 1200 // handle Long.MIN_VALUE case 1201 tempSeconds = tempSeconds + 1; 1202 tempNanos = tempNanos - TimeConstant.NANOS_PER_SECOND; 1203 } 1204 long totalNanos = MathHelper.multiplyExact(tempSeconds , TimeConstant.NANOS_PER_SECOND); 1205 totalNanos = MathHelper.addExact(totalNanos , tempNanos); 1206 return totalNanos; 1207 } 1208 1209 /** 1210 * Extracts the number of days _in the duration. 1211 * !(p) 1212 * This returns the total number of days _in the duration by dividing the 1213 * number of seconds by 86400. 1214 * This is based on the standard definition of a day as 24 hours. 1215 * !(p) 1216 * This instance is immutable and unaffected by this method call. 1217 * 1218 * @return the number of days _in the duration, may be negative 1219 * @since 9 1220 */ 1221 long toDaysPart(){ 1222 return seconds / TimeConstant.SECONDS_PER_DAY; 1223 } 1224 1225 /** 1226 * Extracts the number of hours part _in the duration. 1227 * !(p) 1228 * This returns the number of remaining hours when dividing {@link #toHours} 1229 * by hours _in a day. 1230 * This is based on the standard definition of a day as 24 hours. 1231 * !(p) 1232 * This instance is immutable and unaffected by this method call. 1233 * 1234 * @return the number of hours part _in the duration, may be negative 1235 * @since 9 1236 */ 1237 int toHoursPart(){ 1238 return cast(int) (toHours() % 24); 1239 } 1240 1241 /** 1242 * Extracts the number of minutes part _in the duration. 1243 * !(p) 1244 * This returns the number of remaining minutes when dividing {@link #toMinutes} 1245 * by minutes _in an hour. 1246 * This is based on the standard definition of an hour as 60 minutes. 1247 * !(p) 1248 * This instance is immutable and unaffected by this method call. 1249 * 1250 * @return the number of minutes parts _in the duration, may be negative 1251 * @since 9 1252 */ 1253 int toMinutesPart(){ 1254 return cast(int) (toMinutes() % TimeConstant.MINUTES_PER_HOUR); 1255 } 1256 1257 /** 1258 * Extracts the number of seconds part _in the duration. 1259 * !(p) 1260 * This returns the remaining seconds when dividing {@link #toSeconds} 1261 * by seconds _in a minute. 1262 * This is based on the standard definition of a minute as 60 seconds. 1263 * !(p) 1264 * This instance is immutable and unaffected by this method call. 1265 * 1266 * @return the number of seconds parts _in the duration, may be negative 1267 * @since 9 1268 */ 1269 int toSecondsPart(){ 1270 return cast(int) (seconds % TimeConstant.SECONDS_PER_MINUTE); 1271 } 1272 1273 /** 1274 * Extracts the number of milliseconds part of the duration. 1275 * !(p) 1276 * This returns the milliseconds part by dividing the number of nanoseconds by 1,000,000. 1277 * The length of the duration is stored using two fields - seconds and nanoseconds. 1278 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 1279 * the length _in seconds. 1280 * The total duration is defined by calling {@link #getNano()} and {@link #getSeconds()}. 1281 * !(p) 1282 * This instance is immutable and unaffected by this method call. 1283 * 1284 * @return the number of milliseconds part of the duration. 1285 * @since 9 1286 */ 1287 int toMillisPart(){ 1288 return nanos / 1000_000; 1289 } 1290 1291 /** 1292 * Get the nanoseconds part within seconds of the duration. 1293 * !(p) 1294 * The length of the duration is stored using two fields - seconds and nanoseconds. 1295 * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to 1296 * the length _in seconds. 1297 * The total duration is defined by calling {@link #getNano()} and {@link #getSeconds()}. 1298 * !(p) 1299 * This instance is immutable and unaffected by this method call. 1300 * 1301 * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999 1302 * @since 9 1303 */ 1304 int toNanosPart(){ 1305 return nanos; 1306 } 1307 1308 1309 //----------------------------------------------------------------------- 1310 /** 1311 * Returns a copy of this {@code Duration} truncated to the specified unit. 1312 * !(p) 1313 * Truncating the duration returns a copy of the original with conceptual fields 1314 * smaller than the specified unit set to zero. 1315 * For example, truncating with the {@link ChronoUnit#MINUTES MINUTES} unit will 1316 * round down towards zero to the nearest minute, setting the seconds and 1317 * nanoseconds to zero. 1318 * !(p) 1319 * The unit must have a {@linkplain TemporalUnit#getDuration() duration} 1320 * that divides into the length of a standard day without remainder. 1321 * This includes all 1322 * {@linkplain ChronoUnit#isTimeBased() time-based units on {@code ChronoUnit}} 1323 * and {@link ChronoUnit#DAYS DAYS}. Other ChronoUnits throw an exception. 1324 * !(p) 1325 * This instance is immutable and unaffected by this method call. 1326 * 1327 * @param unit the unit to truncate to, not null 1328 * @return a {@code Duration} based on this duration with the time truncated, not null 1329 * @throws DateTimeException if the unit is invalid for truncation 1330 * @throws UnsupportedTemporalTypeException if the unit is not supported 1331 * @since 9 1332 */ 1333 Duration truncatedTo(TemporalUnit unit) { 1334 assert(unit, "unit"); 1335 if (unit == ChronoUnit.SECONDS && (seconds >= 0 || nanos == 0)) { 1336 return new Duration(seconds, 0); 1337 } else if (unit == ChronoUnit.NANOS) { 1338 return this; 1339 } 1340 Duration unitDur = unit.getDuration(); 1341 if (unitDur.getSeconds() > TimeConstant.SECONDS_PER_DAY) { 1342 throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation"); 1343 } 1344 long dur = unitDur.toNanos(); 1345 if ((TimeConstant.NANOS_PER_DAY % dur) != 0) { 1346 throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder"); 1347 } 1348 long nod = (seconds % TimeConstant.SECONDS_PER_DAY) * TimeConstant.NANOS_PER_SECOND + nanos; 1349 long result = (nod / dur) * dur; 1350 return plusNanos(result - nod); 1351 } 1352 1353 //----------------------------------------------------------------------- 1354 /** 1355 * Compares this duration to the specified {@code Duration}. 1356 * !(p) 1357 * The comparison is based on the total length of the durations. 1358 * It is "consistent with equals", as defined by {@link Comparable}. 1359 * 1360 * @param otherDuration the other duration to compare to, not null 1361 * @return the comparator value, negative if less, positive if greater 1362 */ 1363 // override 1364 int compareTo(Duration otherDuration) { 1365 import hunt.util.Comparator; 1366 1367 int cmp = compare(seconds, otherDuration.seconds); 1368 if (cmp != 0) { 1369 return cmp; 1370 } 1371 return nanos - otherDuration.nanos; 1372 } 1373 1374 //----------------------------------------------------------------------- 1375 /** 1376 * Checks if this duration is equal to the specified {@code Duration}. 1377 * !(p) 1378 * The comparison is based on the total length of the durations. 1379 * 1380 * @param otherDuration the other duration, null returns false 1381 * @return true if the other duration is equal to this one 1382 */ 1383 override 1384 bool opEquals(Object otherDuration) { 1385 if (this == otherDuration) { 1386 return true; 1387 } 1388 if (cast(Duration)(otherDuration) !is null) { 1389 Duration other = cast(Duration) otherDuration; 1390 return this.seconds == other.seconds && 1391 this.nanos == other.nanos; 1392 } 1393 return false; 1394 } 1395 1396 /** 1397 * A hash code for this duration. 1398 * 1399 * @return a suitable hash code 1400 */ 1401 override 1402 size_t toHash() @trusted nothrow { 1403 return (cast(int) (seconds ^ (seconds >>> 32))) + (51 * nanos); 1404 } 1405 1406 //----------------------------------------------------------------------- 1407 /** 1408 * A string representation of this duration using ISO-8601 seconds 1409 * based representation, such as {@code PT8H6M12.345S}. 1410 * !(p) 1411 * The format of the returned string will be {@code PTnHnMnS}, where n is 1412 * the relevant hours, minutes or seconds part of the duration. 1413 * Any fractional seconds are placed after a decimal point _in the seconds section. 1414 * If a section has a zero value, it is omitted. 1415 * The hours, minutes and seconds will all have the same sign. 1416 * !(p) 1417 * Examples: 1418 * !(pre) 1419 * "20.345 seconds" -- "PT20.345S 1420 * "15 minutes" (15 * 60 seconds) -- "PT15M" 1421 * "10 hours" (10 * 3600 seconds) -- "PT10H" 1422 * "2 days" (2 * 86400 seconds) -- "PT48H" 1423 * </pre> 1424 * Note that multiples of 24 hours are not output as days to avoid confusion 1425 * with {@code Period}. 1426 * 1427 * @return an ISO-8601 representation of this duration, not null 1428 */ 1429 override 1430 string toString() { 1431 if (this == ZERO) { 1432 return "PT0S"; 1433 } 1434 long effectiveTotalSecs = seconds; 1435 if (seconds < 0 && nanos > 0) { 1436 effectiveTotalSecs++; 1437 } 1438 long hours = effectiveTotalSecs / TimeConstant.SECONDS_PER_HOUR; 1439 int minutes = cast(int) ((effectiveTotalSecs % TimeConstant.SECONDS_PER_HOUR) / TimeConstant.SECONDS_PER_MINUTE); 1440 int secs = cast(int) (effectiveTotalSecs % TimeConstant.SECONDS_PER_MINUTE); 1441 StringBuilder buf = new StringBuilder(24); 1442 buf.append("PT"); 1443 if (hours != 0) { 1444 buf.append(hours).append('H'); 1445 } 1446 if (minutes != 0) { 1447 buf.append(minutes).append('M'); 1448 } 1449 if (secs == 0 && nanos == 0 && buf.length() > 2) { 1450 return buf.toString(); 1451 } 1452 if (seconds < 0 && nanos > 0) { 1453 if (secs == 0) { 1454 buf.append("-0"); 1455 } else { 1456 buf.append(secs); 1457 } 1458 } else { 1459 buf.append(secs); 1460 } 1461 if (nanos > 0) { 1462 int pos = buf.length(); 1463 if (seconds < 0) { 1464 buf.append(2 * TimeConstant.NANOS_PER_SECOND - nanos); 1465 } else { 1466 buf.append(nanos + TimeConstant.NANOS_PER_SECOND); 1467 } 1468 while (buf.charAt(buf.length() - 1) == '0') { 1469 buf.setLength(buf.length() - 1); 1470 } 1471 buf.setCharAt(pos, '.'); 1472 } 1473 buf.append('S'); 1474 return buf.toString(); 1475 } 1476 1477 //----------------------------------------------------------------------- 1478 /** 1479 * Writes the object using a 1480 * <a href="{@docRoot}/serialized-form.html#hunt.time.Ser">dedicated serialized form</a>. 1481 * @serialData 1482 * !(pre) 1483 * _out.writeByte(1); // identifies a Duration 1484 * _out.writeLong(seconds); 1485 * _out.writeInt(nanos); 1486 * </pre> 1487 * 1488 * @return the instance of {@code Ser}, not null 1489 */ 1490 private Object writeReplace() { 1491 return new Ser(Ser.DURATION_TYPE, this); 1492 } 1493 1494 /** 1495 * Defend against malicious streams. 1496 * 1497 * @param s the stream to read 1498 * @throws InvalidObjectException always 1499 */ 1500 ///@gxc 1501 // private void readObject(ObjectInputStream s) /*throws InvalidObjectException*/ { 1502 // throw new InvalidObjectException("Deserialization via serialization delegate"); 1503 // } 1504 1505 void writeExternal(DataOutput _out) /*throws IOException*/ { 1506 _out.writeLong(seconds); 1507 _out.writeInt(nanos); 1508 } 1509 1510 static Duration readExternal(DataInput _in) /*throws IOException*/ { 1511 long seconds = _in.readLong(); 1512 int nanos = _in.readInt(); 1513 return Duration.ofSeconds(seconds, nanos); 1514 } 1515 1516 override int opCmp(Duration o) 1517 { 1518 auto res = compare(this.seconds,o.seconds); 1519 if(res == 0) 1520 res = compare(this.nanos,o.nanos); 1521 return res; 1522 } 1523 1524 1525 // mixin SerializationMember!(typeof(this)); 1526 }