001/* 002 * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos 003 * 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions are met: 008 * 009 * * Redistributions of source code must retain the above copyright notice, 010 * this list of conditions and the following disclaimer. 011 * 012 * * Redistributions in binary form must reproduce the above copyright notice, 013 * this list of conditions and the following disclaimer in the documentation 014 * and/or other materials provided with the distribution. 015 * 016 * * Neither the name of JSR-310 nor the names of its contributors 017 * may be used to endorse or promote products derived from this software 018 * without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 031 */ 032package org.threeten.bp; 033 034import static org.threeten.bp.LocalTime.NANOS_PER_DAY; 035import static org.threeten.bp.LocalTime.NANOS_PER_HOUR; 036import static org.threeten.bp.LocalTime.NANOS_PER_MINUTE; 037import static org.threeten.bp.LocalTime.NANOS_PER_SECOND; 038import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH; 039import static org.threeten.bp.temporal.ChronoField.EPOCH_MONTH; 040import static org.threeten.bp.temporal.ChronoField.MONTH_OF_YEAR; 041import static org.threeten.bp.temporal.ChronoField.NANO_OF_DAY; 042import static org.threeten.bp.temporal.ChronoField.YEAR; 043import static org.threeten.bp.temporal.ChronoUnit.DAYS; 044import static org.threeten.bp.temporal.ChronoUnit.MONTHS; 045import static org.threeten.bp.temporal.ChronoUnit.NANOS; 046import static org.threeten.bp.temporal.ChronoUnit.YEARS; 047 048import java.io.Serializable; 049import java.util.Objects; 050 051import org.threeten.bp.format.DateTimeParseException; 052import org.threeten.bp.jdk8.Jdk8Methods; 053import org.threeten.bp.temporal.Chrono; 054import org.threeten.bp.temporal.ChronoField; 055import org.threeten.bp.temporal.ChronoUnit; 056import org.threeten.bp.temporal.Temporal; 057import org.threeten.bp.temporal.TemporalAccessor; 058import org.threeten.bp.temporal.TemporalAdder; 059import org.threeten.bp.temporal.TemporalSubtractor; 060import org.threeten.bp.temporal.TemporalUnit; 061import org.threeten.bp.temporal.ValueRange; 062 063/** 064 * A period of time, measured using the most common units, such as '3 Months, 4 Days and 7 Hours'. 065 * <p> 066 * A {@code Period} represents an amount of time measured in terms of the most commonly used units: 067 * <p><ul> 068 * <li>{@link ChronoUnit#YEARS YEARS}</li> 069 * <li>{@link ChronoUnit#MONTHS MONTHS}</li> 070 * <li>{@link ChronoUnit#DAYS DAYS}</li> 071 * <li>time units with an {@link TemporalUnit#isDurationEstimated() exact duration}</li> 072 * </ul><p> 073 * The period may be used with any calendar system with the exception is methods with an "ISO" suffix. 074 * The meaning of a "year" or a "month" is only applied when the object is added to a date. 075 * <p> 076 * The period is modeled as a directed amount of time, meaning that individual parts of the 077 * period may be negative. 078 * 079 * <h3>Specification for implementors</h3> 080 * This class is immutable and thread-safe. 081 * The maximum number of hours that can be stored is about 2.5 million, limited by storing 082 * a single {@code long} nanoseconds for all time units internally. 083 */ 084public final class Period 085 implements TemporalAdder, TemporalSubtractor, Serializable { 086 // maximum hours is 2,562,047 087 088 /** 089 * A constant for a period of zero. 090 */ 091 public static final Period ZERO = new Period(0, 0, 0, 0); 092 /** 093 * Serialization version. 094 */ 095 private static final long serialVersionUID = -8290556941213247973L; 096 097 /** 098 * The number of years. 099 */ 100 private final int years; 101 /** 102 * The number of months. 103 */ 104 private final int months; 105 /** 106 * The number of days. 107 */ 108 private final int days; 109 /** 110 * The number of nanoseconds. 111 */ 112 private final long nanos; 113 114 //----------------------------------------------------------------------- 115 /** 116 * Obtains a {@code Period} from date-based and time-based fields. 117 * <p> 118 * This creates an instance based on years, months, days, hours, minutes and seconds. 119 * Within a period, the time fields are always normalized. 120 * 121 * @param years the amount of years, may be negative 122 * @param months the amount of months, may be negative 123 * @param days the amount of days, may be negative 124 * @param hours the amount of hours, may be negative 125 * @param minutes the amount of minutes, may be negative 126 * @param seconds the amount of seconds, may be negative 127 * @return the period, not null 128 */ 129 public static Period of(int years, int months, int days, int hours, int minutes, int seconds) { 130 return of(years, months, days, hours, minutes, seconds, 0); 131 } 132 133 /** 134 * Obtains a {@code Period} from date-based and time-based fields. 135 * <p> 136 * This creates an instance based on years, months, days, hours, minutes, seconds and nanoseconds. 137 * Within a period, the time fields are always normalized. 138 * 139 * @param years the amount of years, may be negative 140 * @param months the amount of months, may be negative 141 * @param days the amount of days, may be negative 142 * @param hours the amount of hours, may be negative 143 * @param minutes the amount of minutes, may be negative 144 * @param seconds the amount of seconds, may be negative 145 * @param nanos the amount of nanos, may be negative 146 * @return the period, not null 147 */ 148 public static Period of(int years, int months, int days, int hours, int minutes, int seconds, long nanos) { 149 if ((years | months | days | hours | minutes | seconds | nanos) == 0) { 150 return ZERO; 151 } 152 long totSecs = Jdk8Methods.safeAdd(hours * 3600L, minutes * 60L) + seconds; 153 long totNanos = Jdk8Methods.safeAdd(Jdk8Methods.safeMultiply(totSecs, 1_000_000_000L), nanos); 154 return create(years, months, days, totNanos); 155 } 156 157 //----------------------------------------------------------------------- 158 /** 159 * Obtains a {@code Period} from date-based fields. 160 * <p> 161 * This creates an instance based on years, months and days. 162 * 163 * @param years the amount of years, may be negative 164 * @param months the amount of months, may be negative 165 * @param days the amount of days, may be negative 166 * @return the period, not null 167 */ 168 public static Period ofDate(int years, int months, int days) { 169 return of(years, months, days, 0, 0, 0, 0); 170 } 171 172 //----------------------------------------------------------------------- 173 /** 174 * Obtains a {@code Period} from time-based fields. 175 * <p> 176 * This creates an instance based on hours, minutes and seconds. 177 * Within a period, the time fields are always normalized. 178 * 179 * @param hours the amount of hours, may be negative 180 * @param minutes the amount of minutes, may be negative 181 * @param seconds the amount of seconds, may be negative 182 * @return the period, not null 183 */ 184 public static Period ofTime(int hours, int minutes, int seconds) { 185 return of(0, 0, 0, hours, minutes, seconds, 0); 186 } 187 188 /** 189 * Obtains a {@code Period} from time-based fields. 190 * <p> 191 * This creates an instance based on hours, minutes, seconds and nanoseconds. 192 * Within a period, the time fields are always normalized. 193 * 194 * @param hours the amount of hours, may be negative 195 * @param minutes the amount of minutes, may be negative 196 * @param seconds the amount of seconds, may be negative 197 * @param nanos the amount of nanos, may be negative 198 * @return the period, not null 199 */ 200 public static Period ofTime(int hours, int minutes, int seconds, long nanos) { 201 return of(0, 0, 0, hours, minutes, seconds, nanos); 202 } 203 204 //----------------------------------------------------------------------- 205 /** 206 * Obtains an instance of {@code Period} from a period in the specified unit. 207 * <p> 208 * The parameters represent the two parts of a phrase like '6 Days'. For example: 209 * <pre> 210 * Period.of(3, SECONDS); 211 * Period.of(5, YEARS); 212 * </pre> 213 * The specified unit must be one of the supported units from {@link ChronoUnit}, 214 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an 215 * {@link TemporalUnit#isDurationEstimated() exact duration}. 216 * Other units throw an exception. 217 * 218 * @param amount the amount of the period, measured in terms of the unit, positive or negative 219 * @param unit the unit that the period is measured in, must have an exact duration, not null 220 * @return the period, not null 221 * @throws DateTimeException if the period unit is invalid 222 * @throws ArithmeticException if a numeric overflow occurs 223 */ 224 public static Period of(long amount, TemporalUnit unit) { 225 return ZERO.plus(amount, unit); 226 } 227 228 //----------------------------------------------------------------------- 229 /** 230 * Obtains a {@code Period} from a {@code Duration}. 231 * <p> 232 * This converts the duration to a period. 233 * Within a period, the time fields are always normalized. 234 * The years, months and days fields will be zero. 235 * <p> 236 * To populate the days field, call {@link #normalizedHoursToDays()} on the created period. 237 * 238 * @param duration the duration to convert, not null 239 * @return the period, not null 240 * @throws ArithmeticException if numeric overflow occurs 241 */ 242 public static Period of(Duration duration) { 243 Objects.requireNonNull(duration, "duration"); 244 if (duration.isZero()) { 245 return ZERO; 246 } 247 return new Period(0, 0, 0, duration.toNanos()); 248 } 249 250 //----------------------------------------------------------------------- 251 /** 252 * Returns a {@code Period} consisting of the number of years, months, days, 253 * hours, minutes, seconds, and nanoseconds between two {@code TemporalAccessor} instances. 254 * <p> 255 * The start date is included, but the end date is not. Only whole years count. 256 * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days. 257 * <p> 258 * This method examines the {@link ChronoField fields} {@code YEAR}, {@code MONTH_OF_YEAR}, 259 * {@code DAY_OF_MONTH} and {@code NANO_OF_DAY} 260 * The difference between each of the fields is calculated independently from the others. 261 * At least one of the four fields must be present. 262 * <p> 263 * The four units are typically retained without normalization. 264 * However, years and months are normalized if the range of months is fixed, as it is with ISO. 265 * <p> 266 * The result of this method can be a negative period if the end is before the start. 267 * The negative sign can be different in each of the four major units. 268 * 269 * @param start the start date, inclusive, not null 270 * @param end the end date, exclusive, not null 271 * @return the period between the date-times, not null 272 * @throws DateTimeException if the two date-times do have similar available fields 273 * @throws ArithmeticException if numeric overflow occurs 274 */ 275 public static Period between(TemporalAccessor start, TemporalAccessor end) { 276 if (Chrono.from(start).equals(Chrono.from(end)) == false) { 277 throw new DateTimeException("Unable to calculate period as date-times have different chronologies"); 278 } 279 int years = 0; 280 int months = 0; 281 int days = 0; 282 long nanos = 0; 283 boolean valid = false; 284 if (start.isSupported(YEAR)) { 285 years = Jdk8Methods.safeToInt(Jdk8Methods.safeSubtract(end.getLong(YEAR), start.getLong(YEAR))); 286 valid = true; 287 } 288 if (start.isSupported(MONTH_OF_YEAR)) { 289 months = Jdk8Methods.safeToInt(Jdk8Methods.safeSubtract(end.getLong(MONTH_OF_YEAR), start.getLong(MONTH_OF_YEAR))); 290 ValueRange startRange = Chrono.from(start).range(MONTH_OF_YEAR); 291 ValueRange endRange = Chrono.from(end).range(MONTH_OF_YEAR); 292 if (startRange.isFixed() && startRange.isIntValue() && startRange.equals(endRange)) { 293 int monthCount = (int) (startRange.getMaximum() - startRange.getMinimum() + 1); 294 long totMonths = ((long) months) + years * monthCount; 295 months = (int) (totMonths % monthCount); 296 years = Jdk8Methods.safeToInt(totMonths / monthCount); 297 } 298 valid = true; 299 } 300 if (start.isSupported(DAY_OF_MONTH)) { 301 days = Jdk8Methods.safeToInt(Jdk8Methods.safeSubtract(end.getLong(DAY_OF_MONTH), start.getLong(DAY_OF_MONTH))); 302 valid = true; 303 } 304 if (start.isSupported(NANO_OF_DAY)) { 305 nanos = Jdk8Methods.safeSubtract(end.getLong(NANO_OF_DAY), start.getLong(NANO_OF_DAY)); 306 valid = true; 307 } 308 if (valid == false) { 309 throw new DateTimeException("Unable to calculate period as date-times do not have any valid fields"); 310 } 311 return create(years, months, days, nanos); 312 } 313 314 //----------------------------------------------------------------------- 315 /** 316 * Obtains a {@code Period} consisting of the number of years, months, 317 * and days between two dates. 318 * <p> 319 * The start date is included, but the end date is not. 320 * The period is calculated by removing complete months, then calculating 321 * the remaining number of days, adjusting to ensure that both have the same sign. 322 * The number of months is then split into years and months based on a 12 month year. 323 * A month is considered if the end day-of-month is greater than or equal to the start day-of-month. 324 * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days. 325 * <p> 326 * The result of this method can be a negative period if the end is before the start. 327 * The negative sign will be the same in each of year, month and day. 328 * 329 * @param startDate the start date, inclusive, not null 330 * @param endDate the end date, exclusive, not null 331 * @return the period between the dates, not null 332 * @throws ArithmeticException if numeric overflow occurs 333 */ 334 public static Period betweenISO(LocalDate startDate, LocalDate endDate) { 335 long startMonth = startDate.getLong(EPOCH_MONTH); 336 long endMonth = endDate.getLong(EPOCH_MONTH); 337 long totalMonths = endMonth - startMonth; // safe 338 int days = endDate.getDayOfMonth() - startDate.getDayOfMonth(); 339 if (totalMonths > 0 && days < 0) { 340 totalMonths--; 341 LocalDate calcDate = startDate.plusMonths(totalMonths); 342 days = (int) (endDate.toEpochDay() - calcDate.toEpochDay()); // safe 343 } else if (totalMonths < 0 && days > 0) { 344 totalMonths++; 345 days -= endDate.lengthOfMonth(); 346 } 347 long years = totalMonths / 12; // safe 348 int months = (int) (totalMonths % 12); // safe 349 return ofDate(Jdk8Methods.safeToInt(years), months, days); 350 } 351 352 //----------------------------------------------------------------------- 353 /** 354 * Obtains a {@code Period} consisting of the number of hours, minutes, 355 * seconds and nanoseconds between two times. 356 * <p> 357 * The start time is included, but the end time is not. 358 * The period is calculated from the difference between the nano-of-day values 359 * of the two times. For example, from {@code 13:45:00} to {@code 14:50:30.123456789} 360 * is {@code P1H5M30.123456789S}. 361 * <p> 362 * The result of this method can be a negative period if the end is before the start. 363 * 364 * @param startTime the start time, inclusive, not null 365 * @param endTime the end time, exclusive, not null 366 * @return the period between the times, not null 367 * @throws ArithmeticException if numeric overflow occurs 368 */ 369 public static Period betweenISO(LocalTime startTime, LocalTime endTime) { 370 return create(0, 0, 0, endTime.toNanoOfDay() - startTime.toNanoOfDay()); 371 } 372 373 //----------------------------------------------------------------------- 374 /** 375 * Obtains a {@code Period} from a text string such as {@code PnYnMnDTnHnMn.nS}. 376 * <p> 377 * This will parse the string produced by {@code toString()} which is 378 * a subset of the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}. 379 * <p> 380 * The string consists of a series of numbers with a suffix identifying their meaning. 381 * The values, and suffixes, must be in the sequence year, month, day, hour, minute, second. 382 * Any of the number/suffix pairs may be omitted providing at least one is present. 383 * If the period is zero, the value is normally represented as {@code PT0S}. 384 * The numbers must consist of ASCII digits. 385 * Any of the numbers may be negative. Negative zero is not accepted. 386 * The number of nanoseconds is expressed as an optional fraction of the seconds. 387 * There must be at least one digit before any decimal point. 388 * There must be between 1 and 9 inclusive digits after any decimal point. 389 * The letters will all be accepted in upper or lower case. 390 * The decimal point may be either a dot or a comma. 391 * 392 * @param text the text to parse, not null 393 * @return the parsed period, not null 394 * @throws DateTimeParseException if the text cannot be parsed to a period 395 */ 396 public static Period parse(final CharSequence text) { 397 Objects.requireNonNull(text, "text"); 398 return new PeriodParser(text).parse(); 399 } 400 401 //----------------------------------------------------------------------- 402 /** 403 * Creates an instance. 404 * 405 * @param years the amount 406 * @param months the amount 407 * @param days the amount 408 * @param nanos the amount 409 */ 410 private static Period create(int years, int months, int days, long nanos) { 411 if ((years | months | days | nanos) == 0) { 412 return ZERO; 413 } 414 return new Period(years, months, days, nanos); 415 } 416 417 /** 418 * Constructor. 419 * 420 * @param years the amount 421 * @param months the amount 422 * @param days the amount 423 * @param nanos the amount 424 */ 425 private Period(int years, int months, int days, long nanos) { 426 this.years = years; 427 this.months = months; 428 this.days = days; 429 this.nanos = nanos; 430 } 431 432 /** 433 * Resolves singletons. 434 * 435 * @return the resolved instance 436 */ 437 private Object readResolve() { 438 if ((years | months | days | nanos) == 0) { 439 return ZERO; 440 } 441 return this; 442 } 443 444 //----------------------------------------------------------------------- 445 /** 446 * Checks if this period is zero-length. 447 * 448 * @return true if this period is zero-length 449 */ 450 public boolean isZero() { 451 return (this == ZERO); 452 } 453 454 /** 455 * Checks if this period is fully positive, excluding zero. 456 * <p> 457 * This checks whether all the amounts in the period are positive, 458 * defined as greater than zero. 459 * 460 * @return true if this period is fully positive excluding zero 461 */ 462 public boolean isPositive() { 463 return ((years | months | days | nanos) > 0); 464 } 465 466 //----------------------------------------------------------------------- 467 /** 468 * Gets the amount of years of this period. 469 * 470 * @return the amount of years of this period 471 */ 472 public int getYears() { 473 return years; 474 } 475 476 /** 477 * Gets the amount of months of this period. 478 * 479 * @return the amount of months of this period 480 */ 481 public int getMonths() { 482 return months; 483 } 484 485 /** 486 * Gets the amount of days of this period. 487 * 488 * @return the amount of days of this period 489 */ 490 public int getDays() { 491 return days; 492 } 493 494 /** 495 * Gets the amount of hours of this period. 496 * <p> 497 * Within a period, the time fields are always normalized. 498 * 499 * @return the amount of hours of this period 500 */ 501 public int getHours() { 502 return (int) (nanos / NANOS_PER_HOUR); 503 } 504 505 /** 506 * Gets the amount of minutes within an hour of this period. 507 * <p> 508 * Within a period, the time fields are always normalized. 509 * 510 * @return the amount of minutes within an hour of this period 511 */ 512 public int getMinutes() { 513 return (int) ((nanos / NANOS_PER_MINUTE) % 60); 514 } 515 516 /** 517 * Gets the amount of seconds within a minute of this period. 518 * <p> 519 * Within a period, the time fields are always normalized. 520 * 521 * @return the amount of seconds within a minute of this period 522 */ 523 public int getSeconds() { 524 return (int) ((nanos / NANOS_PER_SECOND) % 60); 525 } 526 527 /** 528 * Gets the amount of nanoseconds within a second of this period. 529 * <p> 530 * Within a period, the time fields are always normalized. 531 * 532 * @return the amount of nanoseconds within a second of this period 533 */ 534 public int getNanos() { 535 return (int) (nanos % NANOS_PER_SECOND); // safe from overflow 536 } 537 538 /** 539 * Gets the total amount of the time units of this period, measured in nanoseconds. 540 * <p> 541 * Within a period, the time fields are always normalized. 542 * 543 * @return the total amount of time unit nanoseconds of this period 544 */ 545 public long getTimeNanos() { 546 return nanos; 547 } 548 549 //----------------------------------------------------------------------- 550 /** 551 * Returns a copy of this period with the specified amount of years. 552 * <p> 553 * This method will only affect the years field. 554 * All other units are unaffected. 555 * <p> 556 * This instance is immutable and unaffected by this method call. 557 * 558 * @param years the years to represent 559 * @return a {@code Period} based on this period with the requested years, not null 560 */ 561 public Period withYears(int years) { 562 if (years == this.years) { 563 return this; 564 } 565 return create(years, months, days, nanos); 566 } 567 568 /** 569 * Returns a copy of this period with the specified amount of months. 570 * <p> 571 * This method will only affect the months field. 572 * All other units are unaffected. 573 * <p> 574 * This instance is immutable and unaffected by this method call. 575 * 576 * @param months the months to represent 577 * @return a {@code Period} based on this period with the requested months, not null 578 */ 579 public Period withMonths(int months) { 580 if (months == this.months) { 581 return this; 582 } 583 return create(years, months, days, nanos); 584 } 585 586 /** 587 * Returns a copy of this period with the specified amount of days. 588 * <p> 589 * This method will only affect the days field. 590 * All other units are unaffected. 591 * <p> 592 * This instance is immutable and unaffected by this method call. 593 * 594 * @param days the days to represent 595 * @return a {@code Period} based on this period with the requested days, not null 596 */ 597 public Period withDays(int days) { 598 if (days == this.days) { 599 return this; 600 } 601 return create(years, months, days, nanos); 602 } 603 604 /** 605 * Returns a copy of this period with the specified total amount of time units 606 * expressed in nanoseconds. 607 * <p> 608 * Within a period, the time fields are always normalized. 609 * This method will affect all the time units - hours, minutes, seconds and nanos. 610 * The date units are unaffected. 611 * <p> 612 * This instance is immutable and unaffected by this method call. 613 * 614 * @param nanos the nanoseconds to represent 615 * @return a {@code Period} based on this period with the requested nanoseconds, not null 616 */ 617 public Period withTimeNanos(long nanos) { 618 if (nanos == this.nanos) { 619 return this; 620 } 621 return create(years, months, days, nanos); 622 } 623 624 //----------------------------------------------------------------------- 625 /** 626 * Returns a copy of this period with the specified period added. 627 * <p> 628 * This operates separately on the years, months, days and the normalized time. 629 * There is no further normalization beyond the normalized time. 630 * <p> 631 * This instance is immutable and unaffected by this method call. 632 * 633 * @param other the period to add, not null 634 * @return a {@code Period} based on this period with the requested period added, not null 635 * @throws ArithmeticException if numeric overflow occurs 636 */ 637 public Period plus(Period other) { 638 return create( 639 Jdk8Methods.safeAdd(years, other.years), 640 Jdk8Methods.safeAdd(months, other.months), 641 Jdk8Methods.safeAdd(days, other.days), 642 Jdk8Methods.safeAdd(nanos, other.nanos)); 643 } 644 645 /** 646 * Returns a copy of this period with the specified period added. 647 * <p> 648 * The specified unit must be one of the supported units from {@link ChronoUnit}, 649 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an 650 * {@link TemporalUnit#isDurationEstimated() exact duration}. 651 * Other units throw an exception. 652 * <p> 653 * This instance is immutable and unaffected by this method call. 654 * 655 * @param amount the amount to add, positive or negative 656 * @param unit the unit that the amount is expressed in, not null 657 * @return a {@code Period} based on this period with the requested amount added, not null 658 * @throws ArithmeticException if numeric overflow occurs 659 */ 660 public Period plus(long amount, TemporalUnit unit) { 661 Objects.requireNonNull(unit, "unit"); 662 if (unit instanceof ChronoUnit) { 663 if (unit == YEARS || unit == MONTHS || unit == DAYS || unit.isDurationEstimated() == false) { 664 if (amount == 0) { 665 return this; 666 } 667 switch((ChronoUnit) unit) { 668 case NANOS: return plusNanos(amount); 669 case MICROS: return plusNanos(Jdk8Methods.safeMultiply(amount, 1000L)); 670 case MILLIS: return plusNanos(Jdk8Methods.safeMultiply(amount, 1000_000L)); 671 case SECONDS: return plusSeconds(amount); 672 case MINUTES: return plusMinutes(amount); 673 case HOURS: return plusHours(amount); 674 case HALF_DAYS: return plusNanos(Jdk8Methods.safeMultiply(amount, 12 * NANOS_PER_HOUR)); 675 case DAYS: return plusDays(amount); 676 case MONTHS: return plusMonths(amount); 677 case YEARS: return plusYears(amount); 678 default: throw new DateTimeException("Unsupported unit: " + unit.getName()); 679 } 680 } 681 } 682 if (unit.isDurationEstimated()) { 683 throw new DateTimeException("Unsupported unit: " + unit.getName()); 684 } 685 return plusNanos(Duration.of(amount, unit).toNanos()); 686 } 687 688 public Period plusYears(long amount) { 689 return create(Jdk8Methods.safeToInt(Jdk8Methods.safeAdd(years, amount)), months, days, nanos); 690 } 691 692 public Period plusMonths(long amount) { 693 return create(years, Jdk8Methods.safeToInt(Jdk8Methods.safeAdd(months, amount)), days, nanos); 694 } 695 696 public Period plusDays(long amount) { 697 return create(years, months, Jdk8Methods.safeToInt(Jdk8Methods.safeAdd(days, amount)), nanos); 698 } 699 700 public Period plusHours(long amount) { 701 return plusNanos(Jdk8Methods.safeMultiply(amount, NANOS_PER_HOUR)); 702 } 703 704 public Period plusMinutes(long amount) { 705 return plusNanos(Jdk8Methods.safeMultiply(amount, NANOS_PER_MINUTE)); 706 } 707 708 public Period plusSeconds(long amount) { 709 return plusNanos(Jdk8Methods.safeMultiply(amount, NANOS_PER_SECOND)); 710 } 711 712 public Period plusNanos(long amount) { 713 return create(years, months, days, Jdk8Methods.safeAdd(nanos, amount)); 714 } 715 716 //----------------------------------------------------------------------- 717 /** 718 * Returns a copy of this period with the specified period subtracted. 719 * <p> 720 * This operates separately on the years, months, days and the normalized time. 721 * There is no further normalization beyond the normalized time. 722 * <p> 723 * This instance is immutable and unaffected by this method call. 724 * 725 * @param other the period to subtract, not null 726 * @return a {@code Period} based on this period with the requested period subtracted, not null 727 * @throws ArithmeticException if numeric overflow occurs 728 */ 729 public Period minus(Period other) { 730 return create( 731 Jdk8Methods.safeSubtract(years, other.years), 732 Jdk8Methods.safeSubtract(months, other.months), 733 Jdk8Methods.safeSubtract(days, other.days), 734 Jdk8Methods.safeSubtract(nanos, other.nanos)); 735 } 736 737 /** 738 * Returns a copy of this period with the specified period subtracted. 739 * <p> 740 * The specified unit must be one of the supported units from {@link ChronoUnit}, 741 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an 742 * {@link TemporalUnit#isDurationEstimated() exact duration}. 743 * Other units throw an exception. 744 * <p> 745 * This instance is immutable and unaffected by this method call. 746 * 747 * @param amount the amount to subtract, positive or negative 748 * @param unit the unit that the amount is expressed in, not null 749 * @return a {@code Period} based on this period with the requested amount subtracted, not null 750 * @throws ArithmeticException if numeric overflow occurs 751 */ 752 public Period minus(long amount, TemporalUnit unit) { 753 return (amount == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amount, unit)); 754 } 755 756 public Period minusYears(long amount) { 757 return (amount == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-amount)); 758 } 759 760 public Period minusMonths(long amount) { 761 return (amount == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-amount)); 762 } 763 764 public Period minusDays(long amount) { 765 return (amount == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-amount)); 766 } 767 768 public Period minusHours(long amount) { 769 return (amount == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-amount)); 770 } 771 772 public Period minusMinutes(long amount) { 773 return (amount == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-amount)); 774 } 775 776 public Period minusSeconds(long amount) { 777 return (amount == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-amount)); 778 } 779 780 public Period minusNanos(long amount) { 781 return (amount == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-amount)); 782 } 783 784 //----------------------------------------------------------------------- 785 /** 786 * Returns a new instance with each element in this period multiplied 787 * by the specified scalar. 788 * <p> 789 * This simply multiplies each field, years, months, days and normalized time, 790 * by the scalar. No normalization is performed. 791 * 792 * @param scalar the scalar to multiply by, not null 793 * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null 794 * @throws ArithmeticException if numeric overflow occurs 795 */ 796 public Period multipliedBy(int scalar) { 797 if (this == ZERO || scalar == 1) { 798 return this; 799 } 800 return create( 801 Jdk8Methods.safeMultiply(years, scalar), 802 Jdk8Methods.safeMultiply(months, scalar), 803 Jdk8Methods.safeMultiply(days, scalar), 804 Jdk8Methods.safeMultiply(nanos, scalar)); 805 } 806 807 /** 808 * Returns a new instance with each amount in this period negated. 809 * 810 * @return a {@code Period} based on this period with the amounts negated, not null 811 * @throws ArithmeticException if numeric overflow occurs 812 */ 813 public Period negated() { 814 return multipliedBy(-1); 815 } 816 817 //----------------------------------------------------------------------- 818 /** 819 * Returns a copy of this period with the days and hours normalized using a 24 hour day. 820 * <p> 821 * This normalizes the days and hours units, leaving years and months unchanged. 822 * The hours unit is adjusted to have an absolute value less than 23, 823 * with the days unit being adjusted to compensate. 824 * For example, a period of {@code P1DT27H} will be normalized to {@code P2DT3H}. 825 * <p> 826 * The sign of the days and hours units will be the same after normalization. 827 * For example, a period of {@code P1DT-51H} will be normalized to {@code P-1DT-3H}. 828 * Since all time units are always normalized, if the hours units changes sign then 829 * other time units will also be affected. 830 * <p> 831 * This instance is immutable and unaffected by this method call. 832 * 833 * @return a {@code Period} based on this period with excess hours normalized to days, not null 834 * @throws ArithmeticException if numeric overflow occurs 835 */ 836 public Period normalizedHoursToDays() { 837 // logic uses if statements to normalize signs to avoid unnecessary overflows 838 long totalDays = (nanos / NANOS_PER_DAY) + days; // no overflow 839 long splitNanos = nanos % NANOS_PER_DAY; 840 if (totalDays > 0 && splitNanos < 0) { 841 splitNanos += NANOS_PER_DAY; 842 totalDays--; 843 } else if (totalDays < 0 && splitNanos > 0) { 844 splitNanos -= NANOS_PER_DAY; 845 totalDays++; 846 } 847 if (totalDays == days && splitNanos == nanos) { 848 return this; 849 } 850 return create(years, months, Jdk8Methods.safeToInt(totalDays), splitNanos); 851 } 852 853 /** 854 * Returns a copy of this period with any days converted to hours using a 24 hour day. 855 * <p> 856 * The days unit is reduced to zero, with the hours unit increased by 24 times the 857 * days unit to compensate. Other units are unaffected. 858 * For example, a period of {@code P2DT4H} will be normalized to {@code PT52H}. 859 * <p> 860 * This instance is immutable and unaffected by this method call. 861 * 862 * @return a {@code Period} based on this period with days normalized to hours, not null 863 * @throws ArithmeticException if numeric overflow occurs 864 */ 865 public Period normalizedDaysToHours() { 866 if (days == 0) { 867 return this; 868 } 869 return create(years, months, 0, Jdk8Methods.safeAdd(Jdk8Methods.safeMultiply(days, NANOS_PER_DAY), nanos)); 870 } 871 872 /** 873 * Returns a copy of this period with the years and months normalized using a 12 month year. 874 * <p> 875 * This normalizes the years and months units, leaving other units unchanged. 876 * The months unit is adjusted to have an absolute value less than 11, 877 * with the years unit being adjusted to compensate. 878 * For example, a period of {@code P1Y15M} will be normalized to {@code P2Y3M}. 879 * <p> 880 * The sign of the years and months units will be the same after normalization. 881 * For example, a period of {@code P1Y-25M} will be normalized to {@code P-1Y-1M}. 882 * <p> 883 * This normalization uses a 12 month year it is not valid for all calendar systems. 884 * <p> 885 * This instance is immutable and unaffected by this method call. 886 * 887 * @return a {@code Period} based on this period with years and months normalized, not null 888 * @throws ArithmeticException if numeric overflow occurs 889 */ 890 public Period normalizedMonthsISO() { 891 long totalMonths = years * 12L + months; // no overflow 892 long splitYears = totalMonths / 12; 893 int splitMonths = (int) (totalMonths % 12); // no overflow 894 if (splitYears == years && splitMonths == months) { 895 return this; 896 } 897 return create(Jdk8Methods.safeToInt(splitYears), splitMonths, days, nanos); 898 } 899 900 //------------------------------------------------------------------------- 901 /** 902 * Converts this period to one that only has date units. 903 * <p> 904 * The resulting period will have the same years, months and days as this period 905 * but the time units will all be zero. No normalization occurs in the calculation. 906 * For example, a period of {@code P1Y3MT12H} will be converted to {@code P1Y3M}. 907 * <p> 908 * This instance is immutable and unaffected by this method call. 909 * 910 * @return a {@code Period} based on this period with the time units set to zero, not null 911 */ 912 public Period toDateOnly() { 913 if (nanos == 0) { 914 return this; 915 } 916 return create(years, months, days, 0); 917 } 918 919 //------------------------------------------------------------------------- 920 /** 921 * Adds this period to the specified temporal object. 922 * <p> 923 * This returns a temporal object of the same observable type as the input 924 * with this period added. 925 * <p> 926 * In most cases, it is clearer to reverse the calling pattern by using 927 * {@link Temporal#plus(TemporalAdder)}. 928 * <pre> 929 * // these two lines are equivalent, but the second approach is recommended 930 * dateTime = thisPeriod.addTo(dateTime); 931 * dateTime = dateTime.plus(thisPeriod); 932 * </pre> 933 * <p> 934 * The calculation will add the years, then months, then days, then nanos. 935 * Only non-zero amounts will be added. 936 * If the date-time has a calendar system with a fixed number of months in a 937 * year, then the years and months will be combined before being added. 938 * <p> 939 * This instance is immutable and unaffected by this method call. 940 * 941 * @param temporal the temporal object to adjust, not null 942 * @return an object of the same type with the adjustment made, not null 943 * @throws DateTimeException if unable to add 944 * @throws ArithmeticException if numeric overflow occurs 945 */ 946 @Override 947 public Temporal addTo(Temporal temporal) { 948 Objects.requireNonNull(temporal, "temporal"); 949 if ((years | months) != 0) { 950 ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR); 951 if (startRange.isFixed() && startRange.isIntValue()) { 952 long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1; 953 temporal = temporal.plus(years * monthCount + months, MONTHS); 954 } else { 955 if (years != 0) { 956 temporal = temporal.plus(years, YEARS); 957 } 958 if (months != 0) { 959 temporal = temporal.plus(months, MONTHS); 960 } 961 } 962 } 963 if (days != 0) { 964 temporal = temporal.plus(days, DAYS); 965 } 966 if (nanos != 0) { 967 temporal = temporal.plus(nanos, NANOS); 968 } 969 return temporal; 970 } 971 972 /** 973 * Subtracts this period from the specified temporal object. 974 * <p> 975 * This returns a temporal object of the same observable type as the input 976 * with this period subtracted. 977 * <p> 978 * In most cases, it is clearer to reverse the calling pattern by using 979 * {@link Temporal#minus(TemporalSubtractor)}. 980 * <pre> 981 * // these two lines are equivalent, but the second approach is recommended 982 * dateTime = thisPeriod.subtractFrom(dateTime); 983 * dateTime = dateTime.minus(thisPeriod); 984 * </pre> 985 * <p> 986 * The calculation will subtract the years, then months, then days, then nanos. 987 * Only non-zero amounts will be subtracted. 988 * If the date-time has a calendar system with a fixed number of months in a 989 * year, then the years and months will be combined before being subtracted. 990 * <p> 991 * This instance is immutable and unaffected by this method call. 992 * 993 * @param temporal the temporal object to adjust, not null 994 * @return an object of the same type with the adjustment made, not null 995 * @throws DateTimeException if unable to subtract 996 * @throws ArithmeticException if numeric overflow occurs 997 */ 998 @Override 999 public Temporal subtractFrom(Temporal temporal) { 1000 Objects.requireNonNull(temporal, "temporal"); 1001 if ((years | months) != 0) { 1002 ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR); 1003 if (startRange.isFixed() && startRange.isIntValue()) { 1004 long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1; 1005 temporal = temporal.minus(years * monthCount + months, MONTHS); 1006 } else { 1007 if (years != 0) { 1008 temporal = temporal.minus(years, YEARS); 1009 } 1010 if (months != 0) { 1011 temporal = temporal.minus(months, MONTHS); 1012 } 1013 } 1014 } 1015 if (days != 0) { 1016 temporal = temporal.minus(days, DAYS); 1017 } 1018 if (nanos != 0) { 1019 temporal = temporal.minus(nanos, NANOS); 1020 } 1021 return temporal; 1022 } 1023 1024 //----------------------------------------------------------------------- 1025 /** 1026 * Converts this period to one that only has time units. 1027 * <p> 1028 * The resulting period will have the same time units as this period 1029 * but the date units will all be zero. No normalization occurs in the calculation. 1030 * For example, a period of {@code P1Y3MT12H} will be converted to {@code PT12H}. 1031 * <p> 1032 * This instance is immutable and unaffected by this method call. 1033 * 1034 * @return a {@code Period} based on this period with the date units set to zero, not null 1035 */ 1036 public Period toTimeOnly() { 1037 if ((years | months | days) == 0) { 1038 return this; 1039 } 1040 return create(0, 0, 0, nanos); 1041 } 1042 1043 //------------------------------------------------------------------------- 1044 /** 1045 * Calculates the duration of this period. 1046 * <p> 1047 * The calculation uses the hours, minutes, seconds and nanoseconds fields. 1048 * If years, months or days are present an exception is thrown. 1049 * See {@link #toTimeOnly()} for a way to remove the date units and 1050 * {@link #normalizedDaysToHours()} for a way to convert days to hours. 1051 * 1052 * @return a {@code Duration} equivalent to this period, not null 1053 * @throws DateTimeException if the period cannot be converted as it contains years, months or days 1054 */ 1055 public Duration toDuration() { 1056 if ((years | months | days) != 0) { 1057 throw new DateTimeException("Unable to convert period to duration as years/months/days are present: " + this); 1058 } 1059 return Duration.ofNanos(nanos); 1060 } 1061 1062 //----------------------------------------------------------------------- 1063 /** 1064 * Checks if this period is equal to another period. 1065 * <p> 1066 * The comparison is based on the amounts held in the period. 1067 * To be equal, the years, months, days and normalized time fields must be equal. 1068 * 1069 * @param obj the object to check, null returns false 1070 * @return true if this is equal to the other period 1071 */ 1072 @Override 1073 public boolean equals(Object obj) { 1074 if (this == obj) { 1075 return true; 1076 } 1077 if (obj instanceof Period) { 1078 Period other = (Period) obj; 1079 return years == other.years && months == other.months && 1080 days == other.days && nanos == other.nanos; 1081 } 1082 return false; 1083 } 1084 1085 /** 1086 * A hash code for this period. 1087 * 1088 * @return a suitable hash code 1089 */ 1090 @Override 1091 public int hashCode() { 1092 // ordered such that overflow from one field doesn't immediately affect the next field 1093 return ((years << 27) | (years >>> 5)) ^ 1094 ((days << 21) | (days >>> 11)) ^ 1095 ((months << 17) | (months >>> 15)) ^ 1096 ((int) (nanos ^ (nanos >>> 32))); 1097 } 1098 1099 //----------------------------------------------------------------------- 1100 /** 1101 * Outputs this period as a {@code String}, such as {@code P6Y3M1DT12H}. 1102 * <p> 1103 * The output will be in the ISO-8601 period format. 1104 * 1105 * @return a string representation of this period, not null 1106 */ 1107 @Override 1108 public String toString() { 1109 if (this == ZERO) { 1110 return "PT0S"; 1111 } else { 1112 StringBuilder buf = new StringBuilder(); 1113 buf.append('P'); 1114 if (years != 0) { 1115 buf.append(years).append('Y'); 1116 } 1117 if (months != 0) { 1118 buf.append(months).append('M'); 1119 } 1120 if (days != 0) { 1121 buf.append(days).append('D'); 1122 } 1123 if (nanos != 0) { 1124 buf.append('T'); 1125 if (getHours() != 0) { 1126 buf.append(getHours()).append('H'); 1127 } 1128 if (getMinutes() != 0) { 1129 buf.append(getMinutes()).append('M'); 1130 } 1131 int secondPart = getSeconds(); 1132 int nanoPart = getNanos(); 1133 int secsNanosOr = secondPart | nanoPart; 1134 if (secsNanosOr != 0) { // if either non-zero 1135 if ((secsNanosOr & Integer.MIN_VALUE) != 0) { // if either less than zero 1136 buf.append('-'); 1137 secondPart = Math.abs(secondPart); 1138 nanoPart = Math.abs(nanoPart); 1139 } 1140 buf.append(secondPart); 1141 if (nanoPart != 0) { 1142 int dotPos = buf.length(); 1143 nanoPart += 1000_000_000; 1144 while (nanoPart % 10 == 0) { 1145 nanoPart /= 10; 1146 } 1147 buf.append(nanoPart); 1148 buf.setCharAt(dotPos, '.'); 1149 } 1150 buf.append('S'); 1151 } 1152 } 1153 return buf.toString(); 1154 } 1155 } 1156 1157}