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.temporal.ChronoField.MONTH_OF_YEAR;
  65 import static java.time.temporal.ChronoUnit.DAYS;
  66 import static java.time.temporal.ChronoUnit.MONTHS;
  67 import static java.time.temporal.ChronoUnit.YEARS;
  68 
  69 import java.io.DataInput;
  70 import java.io.DataOutput;
  71 import java.io.IOException;
  72 import java.io.InvalidObjectException;
  73 import java.io.ObjectStreamException;
  74 import java.io.Serializable;
  75 import java.time.chrono.ChronoLocalDate;
  76 import java.time.chrono.Chronology;
  77 import java.time.format.DateTimeParseException;
  78 import java.time.temporal.ChronoUnit;
  79 import java.time.temporal.Temporal;
  80 import java.time.temporal.TemporalAmount;
  81 import java.time.temporal.TemporalUnit;
  82 import java.time.temporal.UnsupportedTemporalTypeException;
  83 import java.time.temporal.ValueRange;
  84 import java.util.Arrays;
  85 import java.util.Collections;
  86 import java.util.List;
  87 import java.util.Objects;
  88 import java.util.regex.Matcher;
  89 import java.util.regex.Pattern;
  90 
  91 /**
  92  * A date-based amount of time, such as '2 years, 3 months and 4 days'.
  93  * <p>
  94  * This class models a quantity or amount of time in terms of years, months and days.
  95  * See {@link Duration} for the time-based equivalent to this class.
  96  * <p>
  97  * Durations and period differ in their treatment of daylight savings time
  98  * when added to {@link ZonedDateTime}. A {@code Duration} will add an exact
  99  * number of seconds, thus a duration of one day is always exactly 24 hours.
 100  * By contrast, a {@code Period} will add a conceptual day, trying to maintain
 101  * the local time.
 102  * <p>
 103  * For example, consider adding a period of one day and a duration of one day to
 104  * 18:00 on the evening before a daylight savings gap. The {@code Period} will add
 105  * the conceptual day and result in a {@code ZonedDateTime} at 18:00 the following day.
 106  * By contrast, the {@code Duration} will add exactly 24 hours, resulting in a
 107  * {@code ZonedDateTime} at 19:00 the following day (assuming a one hour DST gap).
 108  * <p>
 109  * The supported units of a period are {@link ChronoUnit#YEARS YEARS},
 110  * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
 111  * All three fields are always present, but may be set to zero.
 112  * <p>
 113  * The period may be used with any calendar system.
 114  * The meaning of a "year" or "month" is only applied when the object is added to a date.
 115  * <p>
 116  * The period is modeled as a directed amount of time, meaning that individual parts of the
 117  * period may be negative.
 118  * <p>
 119  * The months and years fields may be {@linkplain #normalized() normalized}.
 120  * The normalization assumes a 12 month year, so is not appropriate for all calendar systems.
 121  *
 122  * @implSpec
 123  * This class is immutable and thread-safe.
 124  *
 125  * @since 1.8
 126  */
 127 public final class Period
 128         implements TemporalAmount, Serializable {
 129 
 130     /**
 131      * A constant for a period of zero.
 132      */
 133     public static final Period ZERO = new Period(0, 0, 0);
 134     /**
 135      * Serialization version.
 136      */
 137     private static final long serialVersionUID = -3587258372562876L;
 138     /**
 139      * The pattern for parsing.
 140      */
 141     private final static Pattern PATTERN =
 142             Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
 143     /**
 144      * The set of supported units.
 145      */
 146     private final static List<TemporalUnit> SUPPORTED_UNITS =
 147             Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS));
 148 
 149     /**
 150      * The number of years.
 151      */
 152     private final int years;
 153     /**
 154      * The number of months.
 155      */
 156     private final int months;
 157     /**
 158      * The number of days.
 159      */
 160     private final int days;
 161 
 162     //-----------------------------------------------------------------------
 163     /**
 164      * Obtains a {@code Period} representing a number of years.
 165      * <p>
 166      * The resulting period will have the specified years.
 167      * The months and days units will be zero.
 168      *
 169      * @param years  the number of years, positive or negative
 170      * @return the period of years, not null
 171      */
 172     public static Period ofYears(int years) {
 173         return create(years, 0, 0);
 174     }
 175 
 176     /**
 177      * Obtains a {@code Period} representing a number of months.
 178      * <p>
 179      * The resulting period will have the specified months.
 180      * The years and days units will be zero.
 181      *
 182      * @param months  the number of months, positive or negative
 183      * @return the period of months, not null
 184      */
 185     public static Period ofMonths(int months) {
 186         return create(0, months, 0);
 187     }
 188 
 189     /**
 190      * Obtains a {@code Period} representing a number of days.
 191      * <p>
 192      * The resulting period will have the specified days.
 193      * The years and months units will be zero.
 194      *
 195      * @param days  the number of days, positive or negative
 196      * @return the period of days, not null
 197      */
 198     public static Period ofDays(int days) {
 199         return create(0, 0, days);
 200     }
 201 
 202     //-----------------------------------------------------------------------
 203     /**
 204      * Obtains a {@code Period} representing a number of years, months and days.
 205      * <p>
 206      * This creates an instance based on years, months and days.
 207      *
 208      * @param years  the amount of years, may be negative
 209      * @param months  the amount of months, may be negative
 210      * @param days  the amount of days, may be negative
 211      * @return the period of years, months and days, not null
 212      */
 213     public static Period of(int years, int months, int days) {
 214         return create(years, months, days);
 215     }
 216 
 217     //-----------------------------------------------------------------------
 218     /**
 219      * Obtains an instance of {@code Period} from a temporal amount.
 220      * <p>
 221      * This obtains a period based on the specified amount.
 222      * A {@code TemporalAmount} represents an  amount of time, which may be
 223      * date-based or time-based, which this factory extracts to a period.
 224      * <p>
 225      * The conversion loops around the set of units from the amount and uses
 226      * the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS}
 227      * and {@link ChronoUnit#DAYS DAYS} units to create a period.
 228      * If any other units are found then an exception is thrown.
 229      *
 230      * @param amount  the temporal amount to convert, not null
 231      * @return the equivalent period, not null
 232      * @throws DateTimeException if unable to convert to a {@code Period}
 233      * @throws ArithmeticException if the amount of years, months or days exceeds an int
 234      */
 235     public static Period from(TemporalAmount amount) {
 236         Objects.requireNonNull(amount, "amount");
 237         int years = 0;
 238         int months = 0;
 239         int days = 0;
 240         for (TemporalUnit unit : amount.getUnits()) {
 241             long unitAmount = amount.get(unit);
 242             if (unit == ChronoUnit.YEARS) {
 243                 years = Math.toIntExact(unitAmount);
 244             } else if (unit == ChronoUnit.MONTHS) {
 245                 months = Math.toIntExact(unitAmount);
 246             } else if (unit == ChronoUnit.DAYS) {
 247                 days = Math.toIntExact(unitAmount);
 248             } else {
 249                 throw new DateTimeException("Unit must be Years, Months or Days, but was " + unit);
 250             }
 251         }
 252         return create(years, months, days);
 253     }
 254 
 255     //-----------------------------------------------------------------------
 256     /**
 257      * Obtains a {@code Period} from a text string such as {@code PnYnMnD}.
 258      * <p>
 259      * This will parse the string produced by {@code toString()} which is
 260      * based on the ISO-8601 period format {@code PnYnMnD}.
 261      * <p>
 262      * The string starts with an optional sign, denoted by the ASCII negative
 263      * or positive symbol. If negative, the whole period is negated.
 264      * The ASCII letter "P" is next in upper or lower case.
 265      * There are then three sections, each consisting of a number and a suffix.
 266      * At least one of the three sections must be present.
 267      * The sections have suffixes in ASCII of "Y", "M" and "D" for
 268      * years, months and days, accepted in upper or lower case.
 269      * The suffixes must occur in order.
 270      * The number part of each section must consist of ASCII digits.
 271      * The number may be prefixed by the ASCII negative or positive symbol.
 272      * The number must parse to an {@code int}.
 273      * <p>
 274      * The leading plus/minus sign, and negative values for other units are
 275      * not part of the ISO-8601 standard.
 276      *
 277      * @param text  the text to parse, not null
 278      * @return the parsed period, not null
 279      * @throws DateTimeParseException if the text cannot be parsed to a period
 280      */
 281     public static Period parse(CharSequence text) {
 282         Objects.requireNonNull(text, "text");
 283         Matcher matcher = PATTERN.matcher(text);
 284         if (matcher.matches()) {
 285             int negate = ("-".equals(matcher.group(1)) ? -1 : 1);
 286             String yearMatch = matcher.group(2);
 287             String monthMatch = matcher.group(3);
 288             String dayMatch = matcher.group(4);
 289             if (yearMatch != null || monthMatch != null || dayMatch != null) {
 290                 try {
 291                     return create(parseNumber(text, yearMatch, negate),
 292                             parseNumber(text, monthMatch, negate),
 293                             parseNumber(text, dayMatch, negate));
 294                 } catch (NumberFormatException ex) {
 295                     throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex);
 296                 }
 297             }
 298         }
 299         throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0);
 300     }
 301 
 302     private static int parseNumber(CharSequence text, String str, int negate) {
 303         if (str == null) {
 304             return 0;
 305         }
 306         int val = Integer.parseInt(str);
 307         try {
 308             return Math.multiplyExact(val, negate);
 309         } catch (ArithmeticException ex) {
 310             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex);
 311         }
 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 this date and the end date, not null
 332      * @see ChronoLocalDate#periodUntil(ChronoLocalDate)
 333      */
 334     public static Period between(LocalDate startDate, LocalDate endDate) {
 335         return startDate.periodUntil(endDate);
 336     }
 337 
 338     //-----------------------------------------------------------------------
 339     /**
 340      * Creates an instance.
 341      *
 342      * @param years  the amount
 343      * @param months  the amount
 344      * @param days  the amount
 345      */
 346     private static Period create(int years, int months, int days) {
 347         if ((years | months | days) == 0) {
 348             return ZERO;
 349         }
 350         return new Period(years, months, days);
 351     }
 352 
 353     /**
 354      * Constructor.
 355      *
 356      * @param years  the amount
 357      * @param months  the amount
 358      * @param days  the amount
 359      */
 360     private Period(int years, int months, int days) {
 361         this.years = years;
 362         this.months = months;
 363         this.days = days;
 364     }
 365 
 366     //-----------------------------------------------------------------------
 367     /**
 368      * Gets the value of the requested unit.
 369      * <p>
 370      * This returns a value for each of the three supported units,
 371      * {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS} and
 372      * {@link ChronoUnit#DAYS DAYS}.
 373      * All other units throw an exception.
 374      *
 375      * @param unit the {@code TemporalUnit} for which to return the value
 376      * @return the long value of the unit
 377      * @throws DateTimeException if the unit is not supported
 378      * @throws UnsupportedTemporalTypeException if the unit is not supported
 379      */
 380     @Override
 381     public long get(TemporalUnit unit) {
 382         if (unit == ChronoUnit.YEARS) {
 383             return getYears();
 384         } else if (unit == ChronoUnit.MONTHS) {
 385             return getMonths();
 386         } else if (unit == ChronoUnit.DAYS) {
 387             return getDays();
 388         } else {
 389             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
 390         }
 391     }
 392 
 393     /**
 394      * Gets the set of units supported by this period.
 395      * <p>
 396      * The supported units are {@link ChronoUnit#YEARS YEARS},
 397      * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
 398      * They are returned in the order years, months, days.
 399      * <p>
 400      * This set can be used in conjunction with {@link #get(TemporalUnit)}
 401      * to access the entire state of the period.
 402      *
 403      * @return a list containing the years, months and days units, not null
 404      */
 405     @Override
 406     public List<TemporalUnit> getUnits() {
 407         return SUPPORTED_UNITS;
 408     }
 409 
 410     //-----------------------------------------------------------------------
 411     /**
 412      * Checks if all three units of this period are zero.
 413      * <p>
 414      * A zero period has the value zero for the years, months and days units.
 415      *
 416      * @return true if this period is zero-length
 417      */
 418     public boolean isZero() {
 419         return (this == ZERO);
 420     }
 421 
 422     /**
 423      * Checks if any of the three units of this period are negative.
 424      * <p>
 425      * This checks whether the years, months or days units are less than zero.
 426      *
 427      * @return true if any unit of this period is negative
 428      */
 429     public boolean isNegative() {
 430         return years < 0 || months < 0 || days < 0;
 431     }
 432 
 433     //-----------------------------------------------------------------------
 434     /**
 435      * Gets the amount of years of this period.
 436      * <p>
 437      * This returns the years unit.
 438      * <p>
 439      * The months unit is not normalized with the years unit.
 440      * This means that a period of "15 months" is different to a period
 441      * of "1 year and 3 months".
 442      *
 443      * @return the amount of years of this period, may be negative
 444      */
 445     public int getYears() {
 446         return years;
 447     }
 448 
 449     /**
 450      * Gets the amount of months of this period.
 451      * <p>
 452      * This returns the months unit.
 453      * <p>
 454      * The months unit is not normalized with the years unit.
 455      * This means that a period of "15 months" is different to a period
 456      * of "1 year and 3 months".
 457      *
 458      * @return the amount of months of this period, may be negative
 459      */
 460     public int getMonths() {
 461         return months;
 462     }
 463 
 464     /**
 465      * Gets the amount of days of this period.
 466      * <p>
 467      * This returns the days unit.
 468      *
 469      * @return the amount of days of this period, may be negative
 470      */
 471     public int getDays() {
 472         return days;
 473     }
 474 
 475     //-----------------------------------------------------------------------
 476     /**
 477      * Returns a copy of this period with the specified amount of years.
 478      * <p>
 479      * This sets the amount of the years unit in a copy of this period.
 480      * The months and days units are unaffected.
 481      * <p>
 482      * The months unit is not normalized with the years unit.
 483      * This means that a period of "15 months" is different to a period
 484      * of "1 year and 3 months".
 485      * <p>
 486      * This instance is immutable and unaffected by this method call.
 487      *
 488      * @param years  the years to represent, may be negative
 489      * @return a {@code Period} based on this period with the requested years, not null
 490      */
 491     public Period withYears(int years) {
 492         if (years == this.years) {
 493             return this;
 494         }
 495         return create(years, months, days);
 496     }
 497 
 498     /**
 499      * Returns a copy of this period with the specified amount of months.
 500      * <p>
 501      * This sets the amount of the months unit in a copy of this period.
 502      * The years and days units are unaffected.
 503      * <p>
 504      * The months unit is not normalized with the years unit.
 505      * This means that a period of "15 months" is different to a period
 506      * of "1 year and 3 months".
 507      * <p>
 508      * This instance is immutable and unaffected by this method call.
 509      *
 510      * @param months  the months to represent, may be negative
 511      * @return a {@code Period} based on this period with the requested months, not null
 512      */
 513     public Period withMonths(int months) {
 514         if (months == this.months) {
 515             return this;
 516         }
 517         return create(years, months, days);
 518     }
 519 
 520     /**
 521      * Returns a copy of this period with the specified amount of days.
 522      * <p>
 523      * This sets the amount of the days unit in a copy of this period.
 524      * The years and months units are unaffected.
 525      * <p>
 526      * This instance is immutable and unaffected by this method call.
 527      *
 528      * @param days  the days to represent, may be negative
 529      * @return a {@code Period} based on this period with the requested days, not null
 530      */
 531     public Period withDays(int days) {
 532         if (days == this.days) {
 533             return this;
 534         }
 535         return create(years, months, days);
 536     }
 537 
 538     //-----------------------------------------------------------------------
 539     /**
 540      * Returns a copy of this period with the specified period added.
 541      * <p>
 542      * This operates separately on the years, months and days.
 543      * <p>
 544      * For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days"
 545      * returns "3 years, 8 months and 5 days".
 546      * <p>
 547      * This instance is immutable and unaffected by this method call.
 548      *
 549      * @param amountToAdd  the period to add, not null
 550      * @return a {@code Period} based on this period with the requested period added, not null
 551      * @throws ArithmeticException if numeric overflow occurs
 552      */
 553     public Period plus(Period amountToAdd) {
 554         return create(
 555                 Math.addExact(years, amountToAdd.years),
 556                 Math.addExact(months, amountToAdd.months),
 557                 Math.addExact(days, amountToAdd.days));
 558     }
 559 
 560     /**
 561      * Returns a copy of this period with the specified years added.
 562      * <p>
 563      * This adds the amount to the years unit in a copy of this period.
 564      * The months and days units are unaffected.
 565      * For example, "1 year, 6 months and 3 days" plus 2 years returns "3 years, 6 months and 3 days".
 566      * <p>
 567      * This instance is immutable and unaffected by this method call.
 568      *
 569      * @param yearsToAdd  the years to add, positive or negative
 570      * @return a {@code Period} based on this period with the specified years added, not null
 571      * @throws ArithmeticException if numeric overflow occurs
 572      */
 573     public Period plusYears(long yearsToAdd) {
 574         if (yearsToAdd == 0) {
 575             return this;
 576         }
 577         return create(Math.toIntExact(Math.addExact(years, yearsToAdd)), months, days);
 578     }
 579 
 580     /**
 581      * Returns a copy of this period with the specified months added.
 582      * <p>
 583      * This adds the amount to the months unit in a copy of this period.
 584      * The years and days units are unaffected.
 585      * For example, "1 year, 6 months and 3 days" plus 2 months returns "1 year, 8 months and 3 days".
 586      * <p>
 587      * This instance is immutable and unaffected by this method call.
 588      *
 589      * @param monthsToAdd  the months to add, positive or negative
 590      * @return a {@code Period} based on this period with the specified months added, not null
 591      * @throws ArithmeticException if numeric overflow occurs
 592      */
 593     public Period plusMonths(long monthsToAdd) {
 594         if (monthsToAdd == 0) {
 595             return this;
 596         }
 597         return create(years, Math.toIntExact(Math.addExact(months, monthsToAdd)), days);
 598     }
 599 
 600     /**
 601      * Returns a copy of this period with the specified days added.
 602      * <p>
 603      * This adds the amount to the days unit in a copy of this period.
 604      * The years and months units are unaffected.
 605      * For example, "1 year, 6 months and 3 days" plus 2 days returns "1 year, 6 months and 5 days".
 606      * <p>
 607      * This instance is immutable and unaffected by this method call.
 608      *
 609      * @param daysToAdd  the days to add, positive or negative
 610      * @return a {@code Period} based on this period with the specified days added, not null
 611      * @throws ArithmeticException if numeric overflow occurs
 612      */
 613     public Period plusDays(long daysToAdd) {
 614         if (daysToAdd == 0) {
 615             return this;
 616         }
 617         return create(years, months, Math.toIntExact(Math.addExact(days, daysToAdd)));
 618     }
 619 
 620     //-----------------------------------------------------------------------
 621     /**
 622      * Returns a copy of this period with the specified period subtracted.
 623      * <p>
 624      * This operates separately on the years, months and days.
 625      * <p>
 626      * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days"
 627      * returns "-1 years, 4 months and 1 day".
 628      * <p>
 629      * This instance is immutable and unaffected by this method call.
 630      *
 631      * @param amountToSubtract  the period to subtract, not null
 632      * @return a {@code Period} based on this period with the requested period subtracted, not null
 633      * @throws ArithmeticException if numeric overflow occurs
 634      */
 635     public Period minus(Period amountToSubtract) {
 636         return create(
 637                 Math.subtractExact(years, amountToSubtract.years),
 638                 Math.subtractExact(months, amountToSubtract.months),
 639                 Math.subtractExact(days, amountToSubtract.days));
 640     }
 641 
 642     /**
 643      * Returns a copy of this period with the specified years subtracted.
 644      * <p>
 645      * This subtracts the amount from the years unit in a copy of this period.
 646      * The months and days units are unaffected.
 647      * For example, "1 year, 6 months and 3 days" minus 2 years returns "-1 years, 6 months and 3 days".
 648      * <p>
 649      * This instance is immutable and unaffected by this method call.
 650      *
 651      * @param yearsToSubtract  the years to subtract, positive or negative
 652      * @return a {@code Period} based on this period with the specified years subtracted, not null
 653      * @throws ArithmeticException if numeric overflow occurs
 654      */
 655     public Period minusYears(long yearsToSubtract) {
 656         return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
 657     }
 658 
 659     /**
 660      * Returns a copy of this period with the specified months subtracted.
 661      * <p>
 662      * This subtracts the amount from the months unit in a copy of this period.
 663      * The years and days units are unaffected.
 664      * For example, "1 year, 6 months and 3 days" minus 2 months returns "1 year, 4 months and 3 days".
 665      * <p>
 666      * This instance is immutable and unaffected by this method call.
 667      *
 668      * @param monthsToSubtract  the years to subtract, positive or negative
 669      * @return a {@code Period} based on this period with the specified months subtracted, not null
 670      * @throws ArithmeticException if numeric overflow occurs
 671      */
 672     public Period minusMonths(long monthsToSubtract) {
 673         return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
 674     }
 675 
 676     /**
 677      * Returns a copy of this period with the specified days subtracted.
 678      * <p>
 679      * This subtracts the amount from the days unit in a copy of this period.
 680      * The years and months units are unaffected.
 681      * For example, "1 year, 6 months and 3 days" minus 2 days returns "1 year, 6 months and 1 day".
 682      * <p>
 683      * This instance is immutable and unaffected by this method call.
 684      *
 685      * @param daysToSubtract  the months to subtract, positive or negative
 686      * @return a {@code Period} based on this period with the specified days subtracted, not null
 687      * @throws ArithmeticException if numeric overflow occurs
 688      */
 689     public Period minusDays(long daysToSubtract) {
 690         return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
 691     }
 692 
 693     //-----------------------------------------------------------------------
 694     /**
 695      * Returns a new instance with each element in this period multiplied
 696      * by the specified scalar.
 697      * <p>
 698      * This returns a period with each of the years, months and days units
 699      * individually multiplied.
 700      * For example, a period of "2 years, -3 months and 4 days" multiplied by
 701      * 3 will return "6 years, -9 months and 12 days".
 702      * No normalization is performed.
 703      *
 704      * @param scalar  the scalar to multiply by, not null
 705      * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null
 706      * @throws ArithmeticException if numeric overflow occurs
 707      */
 708     public Period multipliedBy(int scalar) {
 709         if (this == ZERO || scalar == 1) {
 710             return this;
 711         }
 712         return create(
 713                 Math.multiplyExact(years, scalar),
 714                 Math.multiplyExact(months, scalar),
 715                 Math.multiplyExact(days, scalar));
 716     }
 717 
 718     /**
 719      * Returns a new instance with each amount in this period negated.
 720      * <p>
 721      * This returns a period with each of the years, months and days units
 722      * individually negated.
 723      * For example, a period of "2 years, -3 months and 4 days" will be
 724      * negated to "-2 years, 3 months and -4 days".
 725      * No normalization is performed.
 726      *
 727      * @return a {@code Period} based on this period with the amounts negated, not null
 728      * @throws ArithmeticException if numeric overflow occurs, which only happens if
 729      *  one of the units has the value {@code Long.MIN_VALUE}
 730      */
 731     public Period negated() {
 732         return multipliedBy(-1);
 733     }
 734 
 735     //-----------------------------------------------------------------------
 736     /**
 737      * Returns a copy of this period with the years and months normalized
 738      * using a 12 month year.
 739      * <p>
 740      * This normalizes the years and months units, leaving the days unit unchanged.
 741      * The months unit is adjusted to have an absolute value less than 11,
 742      * with the years unit being adjusted to compensate. For example, a period of
 743      * "1 Year and 15 months" will be normalized to "2 years and 3 months".
 744      * <p>
 745      * The sign of the years and months units will be the same after normalization.
 746      * For example, a period of "1 year and -25 months" will be normalized to
 747      * "-1 year and -1 month".
 748      * <p>
 749      * This normalization uses a 12 month year which is not valid for all calendar systems.
 750      * <p>
 751      * This instance is immutable and unaffected by this method call.
 752      *
 753      * @return a {@code Period} based on this period with excess months normalized to years, not null
 754      * @throws ArithmeticException if numeric overflow occurs
 755      */
 756     public Period normalized() {
 757         long totalMonths = toTotalMonths();
 758         long splitYears = totalMonths / 12;
 759         int splitMonths = (int) (totalMonths % 12);  // no overflow
 760         if (splitYears == years && splitMonths == months) {
 761             return this;
 762         }
 763         return create(Math.toIntExact(splitYears), splitMonths, days);
 764     }
 765 
 766     /**
 767      * Gets the total number of months in this period using a 12 month year.
 768      * <p>
 769      * This returns the total number of months in the period by multiplying the
 770      * number of years by 12 and adding the number of months.
 771      * <p>
 772      * This uses a 12 month year which is not valid for all calendar systems.
 773      * <p>
 774      * This instance is immutable and unaffected by this method call.
 775      *
 776      * @return the total number of months in the period, may be negative
 777      */
 778     public long toTotalMonths() {
 779         return years * 12L + months;  // no overflow
 780     }
 781 
 782     //-------------------------------------------------------------------------
 783     /**
 784      * Adds this period to the specified temporal object.
 785      * <p>
 786      * This returns a temporal object of the same observable type as the input
 787      * with this period added.
 788      * <p>
 789      * In most cases, it is clearer to reverse the calling pattern by using
 790      * {@link Temporal#plus(TemporalAmount)}.
 791      * <pre>
 792      *   // these two lines are equivalent, but the second approach is recommended
 793      *   dateTime = thisPeriod.addTo(dateTime);
 794      *   dateTime = dateTime.plus(thisPeriod);
 795      * </pre>
 796      * <p>
 797      * The calculation will add the years, then months, then days.
 798      * Only non-zero amounts will be added.
 799      * If the date-time has a calendar system with a fixed number of months in a
 800      * year, then the years and months will be combined before being added.
 801      * <p>
 802      * This instance is immutable and unaffected by this method call.
 803      *
 804      * @param temporal  the temporal object to adjust, not null
 805      * @return an object of the same type with the adjustment made, not null
 806      * @throws DateTimeException if unable to add
 807      * @throws ArithmeticException if numeric overflow occurs
 808      */
 809     @Override
 810     public Temporal addTo(Temporal temporal) {
 811         Objects.requireNonNull(temporal, "temporal");
 812         if ((years | months) != 0) {
 813             long monthRange = monthRange(temporal);
 814             if (monthRange >= 0) {
 815                 temporal = temporal.plus(years * monthRange + months, MONTHS);
 816             } else {
 817                 if (years != 0) {
 818                     temporal = temporal.plus(years, YEARS);
 819                 }
 820                 if (months != 0) {
 821                     temporal = temporal.plus(months, MONTHS);
 822                 }
 823             }
 824         }
 825         if (days != 0) {
 826             temporal = temporal.plus(days, DAYS);
 827         }
 828         return temporal;
 829     }
 830 
 831     /**
 832      * Subtracts this period from the specified temporal object.
 833      * <p>
 834      * This returns a temporal object of the same observable type as the input
 835      * with this period subtracted.
 836      * <p>
 837      * In most cases, it is clearer to reverse the calling pattern by using
 838      * {@link Temporal#minus(TemporalAmount)}.
 839      * <pre>
 840      *   // these two lines are equivalent, but the second approach is recommended
 841      *   dateTime = thisPeriod.subtractFrom(dateTime);
 842      *   dateTime = dateTime.minus(thisPeriod);
 843      * </pre>
 844      * <p>
 845      * The calculation will subtract the years, then months, then days.
 846      * Only non-zero amounts will be subtracted.
 847      * If the date-time has a calendar system with a fixed number of months in a
 848      * year, then the years and months will be combined before being subtracted.
 849      * <p>
 850      * This instance is immutable and unaffected by this method call.
 851      *
 852      * @param temporal  the temporal object to adjust, not null
 853      * @return an object of the same type with the adjustment made, not null
 854      * @throws DateTimeException if unable to subtract
 855      * @throws ArithmeticException if numeric overflow occurs
 856      */
 857     @Override
 858     public Temporal subtractFrom(Temporal temporal) {
 859         Objects.requireNonNull(temporal, "temporal");
 860         if ((years | months) != 0) {
 861             long monthRange = monthRange(temporal);
 862             if (monthRange >= 0) {
 863                 temporal = temporal.minus(years * monthRange + months, MONTHS);
 864             } else {
 865                 if (years != 0) {
 866                     temporal = temporal.minus(years, YEARS);
 867                 }
 868                 if (months != 0) {
 869                     temporal = temporal.minus(months, MONTHS);
 870                 }
 871             }
 872         }
 873         if (days != 0) {
 874             temporal = temporal.minus(days, DAYS);
 875         }
 876         return temporal;
 877     }
 878 
 879     /**
 880      * Calculates the range of months based on the temporal.
 881      *
 882      * @param temporal  the temporal, not null
 883      * @return the month range, negative if not fixed range
 884      */
 885     private long monthRange(Temporal temporal) {
 886         if (temporal.isSupported(MONTH_OF_YEAR)) {
 887             ValueRange startRange = Chronology.from(temporal).range(MONTH_OF_YEAR);
 888             if (startRange.isFixed() && startRange.isIntValue()) {
 889                 return startRange.getMaximum() - startRange.getMinimum() + 1;
 890             }
 891         }
 892         return -1;
 893     }
 894 
 895     //-----------------------------------------------------------------------
 896     /**
 897      * Checks if this period is equal to another period.
 898      * <p>
 899      * The comparison is based on the amounts held in the period.
 900      * To be equal, the years, months and days units must be individually equal.
 901      * Note that this means that a period of "15 Months" is not equal to a period
 902      * of "1 Year and 3 Months".
 903      *
 904      * @param obj  the object to check, null returns false
 905      * @return true if this is equal to the other period
 906      */
 907     @Override
 908     public boolean equals(Object obj) {
 909         if (this == obj) {
 910             return true;
 911         }
 912         if (obj instanceof Period) {
 913             Period other = (Period) obj;
 914             return years == other.years &&
 915                     months == other.months &&
 916                     days == other.days;
 917         }
 918         return false;
 919     }
 920 
 921     /**
 922      * A hash code for this period.
 923      *
 924      * @return a suitable hash code
 925      */
 926     @Override
 927     public int hashCode() {
 928         return years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16);
 929     }
 930 
 931     //-----------------------------------------------------------------------
 932     /**
 933      * Outputs this period as a {@code String}, such as {@code P6Y3M1D}.
 934      * <p>
 935      * The output will be in the ISO-8601 period format.
 936      * A zero period will be represented as zero days, 'P0D'.
 937      *
 938      * @return a string representation of this period, not null
 939      */
 940     @Override
 941     public String toString() {
 942         if (this == ZERO) {
 943             return "P0D";
 944         } else {
 945             StringBuilder buf = new StringBuilder();
 946             buf.append('P');
 947             if (years != 0) {
 948                 buf.append(years).append('Y');
 949             }
 950             if (months != 0) {
 951                 buf.append(months).append('M');
 952             }
 953             if (days != 0) {
 954                 buf.append(days).append('D');
 955             }
 956             return buf.toString();
 957         }
 958     }
 959 
 960     //-----------------------------------------------------------------------
 961     /**
 962      * Writes the object using a
 963      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
 964      * <pre>
 965      *  out.writeByte(14);  // identifies this as a Period
 966      *  out.writeInt(years);
 967      *  out.writeInt(months);
 968      *  out.writeInt(seconds);
 969      * </pre>
 970      *
 971      * @return the instance of {@code Ser}, not null
 972      */
 973     private Object writeReplace() {
 974         return new Ser(Ser.PERIOD_TYPE, this);
 975     }
 976 
 977     /**
 978      * Defend against malicious streams.
 979      * @return never
 980      * @throws java.io.InvalidObjectException always
 981      */
 982     private Object readResolve() throws ObjectStreamException {
 983         throw new InvalidObjectException("Deserialization via serialization delegate");
 984     }
 985 
 986     void writeExternal(DataOutput out) throws IOException {
 987         out.writeInt(years);
 988         out.writeInt(months);
 989         out.writeInt(days);
 990     }
 991 
 992     static Period readExternal(DataInput in) throws IOException {
 993         int years = in.readInt();
 994         int months = in.readInt();
 995         int days = in.readInt();
 996         return Period.of(years, months, days);
 997     }
 998 
 999 }