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