1 /*
2  * Copyright (c) 2012, 2018, 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.ChronoUnit.DAYS;
65 import static java.time.temporal.ChronoUnit.MONTHS;
66 import static java.time.temporal.ChronoUnit.YEARS;
67
68 import java.io.DataInput;
69 import java.io.DataOutput;
70 import java.io.IOException;
71 import java.io.InvalidObjectException;
72 import java.io.ObjectInputStream;
73 import java.io.Serializable;
74 import java.time.chrono.ChronoLocalDate;
75 import java.time.chrono.ChronoPeriod;
76 import java.time.chrono.Chronology;
77 import java.time.chrono.IsoChronology;
78 import java.time.format.DateTimeParseException;
79 import java.time.temporal.ChronoUnit;
80 import java.time.temporal.Temporal;
81 import java.time.temporal.TemporalAccessor;
82 import java.time.temporal.TemporalAmount;
83 import java.time.temporal.TemporalQueries;
84 import java.time.temporal.TemporalUnit;
85 import java.time.temporal.UnsupportedTemporalTypeException;
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 in the ISO-8601 calendar system,
93  * such as '2 years, 3 months and 4 days'.
94  * <p>
95  * This class models a quantity or amount of time in terms of years, months and days.
96  * See {@link Duration} for the time-based equivalent to this class.
97  * <p>
98  * Durations and periods differ in their treatment of daylight savings time
99  * when added to {@link ZonedDateTime}. A {@code Duration} will add an exact
100  * number of seconds, thus a duration of one day is always exactly 24 hours.
101  * By contrast, a {@code Period} will add a conceptual day, trying to maintain
102  * the local time.
103  * <p>
104  * For example, consider adding a period of one day and a duration of one day to
105  * 18:00 on the evening before a daylight savings gap. The {@code Period} will add
106  * the conceptual day and result in a {@code ZonedDateTime} at 18:00 the following day.
107  * By contrast, the {@code Duration} will add exactly 24 hours, resulting in a
108  * {@code ZonedDateTime} at 19:00 the following day (assuming a one hour DST gap).
109  * <p>
110  * The supported units of a period are {@link ChronoUnit#YEARS YEARS},
111  * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
112  * All three fields are always present, but may be set to zero.
113  * <p>
114  * The ISO-8601 calendar system is the modern civil calendar system used today
115  * in most of the world. It is equivalent to the proleptic Gregorian calendar
116  * system, in which today's rules for leap years are applied for all time.
117  * <p>
118  * The period is modeled as a directed amount of time, meaning that individual parts of the
119  * period may be negative.
120  *
121  * <p>
122  * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
123  * class; use of identity-sensitive operations (including reference equality
124  * ({@code ==}), identity hash code, or synchronization) on instances of
125  * {@code Period} may have unpredictable results and should be avoided.
126  * The {@code equals} method should be used for comparisons.
127  *
128  * @implSpec
129  * This class is immutable and thread-safe.
130  *
131  * @since 1.8
132  */

133 public final class Period
134         implements ChronoPeriod, Serializable {
135
136     /**
137      * A constant for a period of zero.
138      */

139     public static final Period ZERO = new Period(0, 0, 0);
140     /**
141      * Serialization version.
142      */

143     private static final long serialVersionUID = -3587258372562876L;
144     /**
145      * The pattern for parsing.
146      */

147     private static final Pattern PATTERN =
148             Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
149
150     /**
151      * The set of supported units.
152      */

153     private static final List<TemporalUnit> SUPPORTED_UNITS = List.of(YEARS, MONTHS, DAYS);
154
155     /**
156      * The number of years.
157      */

158     private final int years;
159     /**
160      * The number of months.
161      */

162     private final int months;
163     /**
164      * The number of days.
165      */

166     private final int days;
167
168     //-----------------------------------------------------------------------
169     /**
170      * Obtains a {@code Period} representing a number of years.
171      * <p>
172      * The resulting period will have the specified years.
173      * The months and days units will be zero.
174      *
175      * @param years  the number of years, positive or negative
176      * @return the period of years, not null
177      */

178     public static Period ofYears(int years) {
179         return create(years, 0, 0);
180     }
181
182     /**
183      * Obtains a {@code Period} representing a number of months.
184      * <p>
185      * The resulting period will have the specified months.
186      * The years and days units will be zero.
187      *
188      * @param months  the number of months, positive or negative
189      * @return the period of months, not null
190      */

191     public static Period ofMonths(int months) {
192         return create(0, months, 0);
193     }
194
195     /**
196      * Obtains a {@code Period} representing a number of weeks.
197      * <p>
198      * The resulting period will be day-based, with the amount of days
199      * equal to the number of weeks multiplied by 7.
200      * The years and months units will be zero.
201      *
202      * @param weeks  the number of weeks, positive or negative
203      * @return the period, with the input weeks converted to days, not null
204      */

205     public static Period ofWeeks(int weeks) {
206         return create(0, 0, Math.multiplyExact(weeks, 7));
207     }
208
209     /**
210      * Obtains a {@code Period} representing a number of days.
211      * <p>
212      * The resulting period will have the specified days.
213      * The years and months units will be zero.
214      *
215      * @param days  the number of days, positive or negative
216      * @return the period of days, not null
217      */

218     public static Period ofDays(int days) {
219         return create(0, 0, days);
220     }
221
222     //-----------------------------------------------------------------------
223     /**
224      * Obtains a {@code Period} representing a number of years, months and days.
225      * <p>
226      * This creates an instance based on years, months and days.
227      *
228      * @param years  the amount of years, may be negative
229      * @param months  the amount of months, may be negative
230      * @param days  the amount of days, may be negative
231      * @return the period of years, months and days, not null
232      */

233     public static Period of(int years, int months, int days) {
234         return create(years, months, days);
235     }
236
237     //-----------------------------------------------------------------------
238     /**
239      * Obtains an instance of {@code Period} from a temporal amount.
240      * <p>
241      * This obtains a period based on the specified amount.
242      * A {@code TemporalAmount} represents an  amount of time, which may be
243      * date-based or time-based, which this factory extracts to a {@code Period}.
244      * <p>
245      * The conversion loops around the set of units from the amount and uses
246      * the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS}
247      * and {@link ChronoUnit#DAYS DAYS} units to create a period.
248      * If any other units are found then an exception is thrown.
249      * <p>
250      * If the amount is a {@code ChronoPeriod} then it must use the ISO chronology.
251      *
252      * @param amount  the temporal amount to convert, not null
253      * @return the equivalent period, not null
254      * @throws DateTimeException if unable to convert to a {@code Period}
255      * @throws ArithmeticException if the amount of years, months or days exceeds an int
256      */

257     public static Period from(TemporalAmount amount) {
258         if (amount instanceof Period) {
259             return (Period) amount;
260         }
261         if (amount instanceof ChronoPeriod) {
262             if (IsoChronology.INSTANCE.equals(((ChronoPeriod) amount).getChronology()) == false) {
263                 throw new DateTimeException("Period requires ISO chronology: " + amount);
264             }
265         }
266         Objects.requireNonNull(amount, "amount");
267         int years = 0;
268         int months = 0;
269         int days = 0;
270         for (TemporalUnit unit : amount.getUnits()) {
271             long unitAmount = amount.get(unit);
272             if (unit == ChronoUnit.YEARS) {
273                 years = Math.toIntExact(unitAmount);
274             } else if (unit == ChronoUnit.MONTHS) {
275                 months = Math.toIntExact(unitAmount);
276             } else if (unit == ChronoUnit.DAYS) {
277                 days = Math.toIntExact(unitAmount);
278             } else {
279                 throw new DateTimeException("Unit must be Years, Months or Days, but was " + unit);
280             }
281         }
282         return create(years, months, days);
283     }
284
285     //-----------------------------------------------------------------------
286     /**
287      * Obtains a {@code Period} from a text string such as {@code PnYnMnD}.
288      * <p>
289      * This will parse the string produced by {@code toString()} which is
290      * based on the ISO-8601 period formats {@code PnYnMnD} and {@code PnW}.
291      * <p>
292      * The string starts with an optional sign, denoted by the ASCII negative
293      * or positive symbol. If negative, the whole period is negated.
294      * The ASCII letter "P" is next in upper or lower case.
295      * There are then four sections, each consisting of a number and a suffix.
296      * At least one of the four sections must be present.
297      * The sections have suffixes in ASCII of "Y""M""W" and "D" for
298      * years, months, weeks and days, accepted in upper or lower case.
299      * The suffixes must occur in order.
300      * The number part of each section must consist of ASCII digits.
301      * The number may be prefixed by the ASCII negative or positive symbol.
302      * The number must parse to an {@code int}.
303      * <p>
304      * The leading plus/minus sign, and negative values for other units are
305      * not part of the ISO-8601 standard. In addition, ISO-8601 does not
306      * permit mixing between the {@code PnYnMnD} and {@code PnW} formats.
307      * Any week-based input is multiplied by 7 and treated as a number of days.
308      * <p>
309      * For example, the following are valid inputs:
310      * <pre>
311      *   "P2Y"             -- Period.ofYears(2)
312      *   "P3M"             -- Period.ofMonths(3)
313      *   "P4W"             -- Period.ofWeeks(4)
314      *   "P5D"             -- Period.ofDays(5)
315      *   "P1Y2M3D"         -- Period.of(1, 2, 3)
316      *   "P1Y2M3W4D"       -- Period.of(1, 2, 25)
317      *   "P-1Y2M"          -- Period.of(-1, 2, 0)
318      *   "-P1Y2M"          -- Period.of(-1, -2, 0)
319      * </pre>
320      *
321      * @param text  the text to parse, not null
322      * @return the parsed period, not null
323      * @throws DateTimeParseException if the text cannot be parsed to a period
324      */

325     public static Period parse(CharSequence text) {
326         Objects.requireNonNull(text, "text");
327         Matcher matcher = PATTERN.matcher(text);
328         if (matcher.matches()) {
329             int negate = (charMatch(text, matcher.start(1), matcher.end(1), '-') ? -1 : 1);
330             int yearStart = matcher.start(2), yearEnd = matcher.end(2);
331             int monthStart = matcher.start(3), monthEnd = matcher.end(3);
332             int weekStart = matcher.start(4), weekEnd = matcher.end(4);
333             int dayStart = matcher.start(5), dayEnd = matcher.end(5);
334             if (yearStart >= 0 || monthStart >= 0 || weekStart >= 0 || dayStart >= 0) {
335                 try {
336                     int years = parseNumber(text, yearStart, yearEnd, negate);
337                     int months = parseNumber(text, monthStart, monthEnd, negate);
338                     int weeks = parseNumber(text, weekStart, weekEnd, negate);
339                     int days = parseNumber(text, dayStart, dayEnd, negate);
340                     days = Math.addExact(days, Math.multiplyExact(weeks, 7));
341                     return create(years, months, days);
342                 } catch (NumberFormatException ex) {
343                     throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
344                 }
345             }
346         }
347         throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0);
348     }
349
350     private static boolean charMatch(CharSequence text, int start, int end, char c) {
351         return (start >= 0 && end == start + 1 && text.charAt(start) == c);
352     }
353
354     private static int parseNumber(CharSequence text, int start, int end, int negate) {
355         if (start < 0 || end < 0) {
356             return 0;
357         }
358         int val = Integer.parseInt(text, start, end, 10);
359         try {
360             return Math.multiplyExact(val, negate);
361         } catch (ArithmeticException ex) {
362             throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
363         }
364     }
365
366     //-----------------------------------------------------------------------
367     /**
368      * Obtains a {@code Period} consisting of the number of years, months,
369      * and days between two dates.
370      * <p>
371      * The start date is included, but the end date is not.
372      * The period is calculated by removing complete months, then calculating
373      * the remaining number of days, adjusting to ensure that both have the same sign.
374      * The number of months is then split into years and months based on a 12 month year.
375      * A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
376      * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
377      * <p>
378      * The result of this method can be a negative period if the end is before the start.
379      * The negative sign will be the same in each of year, month and day.
380      *
381      * @param startDateInclusive  the start date, inclusive, not null
382      * @param endDateExclusive  the end date, exclusive, not null
383      * @return the period between this date and the end date, not null
384      * @see ChronoLocalDate#until(ChronoLocalDate)
385      */

386     public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) {
387         return startDateInclusive.until(endDateExclusive);
388     }
389
390     //-----------------------------------------------------------------------
391     /**
392      * Creates an instance.
393      *
394      * @param years  the amount
395      * @param months  the amount
396      * @param days  the amount
397      */

398     private static Period create(int years, int months, int days) {
399         if ((years | months | days) == 0) {
400             return ZERO;
401         }
402         return new Period(years, months, days);
403     }
404
405     /**
406      * Constructor.
407      *
408      * @param years  the amount
409      * @param months  the amount
410      * @param days  the amount
411      */

412     private Period(int years, int months, int days) {
413         this.years = years;
414         this.months = months;
415         this.days = days;
416     }
417
418     //-----------------------------------------------------------------------
419     /**
420      * Gets the value of the requested unit.
421      * <p>
422      * This returns a value for each of the three supported units,
423      * {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS} and
424      * {@link ChronoUnit#DAYS DAYS}.
425      * All other units throw an exception.
426      *
427      * @param unit the {@code TemporalUnit} for which to return the value
428      * @return the long value of the unit
429      * @throws DateTimeException if the unit is not supported
430      * @throws UnsupportedTemporalTypeException if the unit is not supported
431      */

432     @Override
433     public long get(TemporalUnit unit) {
434         if (unit == ChronoUnit.YEARS) {
435             return getYears();
436         } else if (unit == ChronoUnit.MONTHS) {
437             return getMonths();
438         } else if (unit == ChronoUnit.DAYS) {
439             return getDays();
440         } else {
441             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
442         }
443     }
444
445     /**
446      * Gets the set of units supported by this period.
447      * <p>
448      * The supported units are {@link ChronoUnit#YEARS YEARS},
449      * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
450      * They are returned in the order years, months, days.
451      * <p>
452      * This set can be used in conjunction with {@link #get(TemporalUnit)}
453      * to access the entire state of the period.
454      *
455      * @return a list containing the years, months and days units, not null
456      */

457     @Override
458     public List<TemporalUnit> getUnits() {
459         return SUPPORTED_UNITS;
460     }
461
462     /**
463      * Gets the chronology of this period, which is the ISO calendar system.
464      * <p>
465      * The {@code Chronology} represents the calendar system in use.
466      * The ISO-8601 calendar system is the modern civil calendar system used today
467      * in most of the world. It is equivalent to the proleptic Gregorian calendar
468      * system, in which today's rules for leap years are applied for all time.
469      *
470      * @return the ISO chronology, not null
471      */

472     @Override
473     public IsoChronology getChronology() {
474         return IsoChronology.INSTANCE;
475     }
476
477     //-----------------------------------------------------------------------
478     /**
479      * Checks if all three units of this period are zero.
480      * <p>
481      * A zero period has the value zero for the years, months and days units.
482      *
483      * @return true if this period is zero-length
484      */

485     public boolean isZero() {
486         return (this == ZERO);
487     }
488
489     /**
490      * Checks if any of the three units of this period are negative.
491      * <p>
492      * This checks whether the years, months or days units are less than zero.
493      *
494      * @return true if any unit of this period is negative
495      */

496     public boolean isNegative() {
497         return years < 0 || months < 0 || days < 0;
498     }
499
500     //-----------------------------------------------------------------------
501     /**
502      * Gets the amount of years of this period.
503      * <p>
504      * This returns the years unit.
505      * <p>
506      * The months unit is not automatically normalized with the years unit.
507      * This means that a period of "15 months" is different to a period
508      * of "1 year and 3 months".
509      *
510      * @return the amount of years of this period, may be negative
511      */

512     public int getYears() {
513         return years;
514     }
515
516     /**
517      * Gets the amount of months of this period.
518      * <p>
519      * This returns the months unit.
520      * <p>
521      * The months unit is not automatically normalized with the years unit.
522      * This means that a period of "15 months" is different to a period
523      * of "1 year and 3 months".
524      *
525      * @return the amount of months of this period, may be negative
526      */

527     public int getMonths() {
528         return months;
529     }
530
531     /**
532      * Gets the amount of days of this period.
533      * <p>
534      * This returns the days unit.
535      *
536      * @return the amount of days of this period, may be negative
537      */

538     public int getDays() {
539         return days;
540     }
541
542     //-----------------------------------------------------------------------
543     /**
544      * Returns a copy of this period with the specified amount of years.
545      * <p>
546      * This sets the amount of the years unit in a copy of this period.
547      * The months and days units are unaffected.
548      * <p>
549      * The months unit is not automatically normalized with the years unit.
550      * This means that a period of "15 months" is different to a period
551      * of "1 year and 3 months".
552      * <p>
553      * This instance is immutable and unaffected by this method call.
554      *
555      * @param years  the years to represent, may be negative
556      * @return a {@code Period} based on this period with the requested years, not null
557      */

558     public Period withYears(int years) {
559         if (years == this.years) {
560             return this;
561         }
562         return create(years, months, days);
563     }
564
565     /**
566      * Returns a copy of this period with the specified amount of months.
567      * <p>
568      * This sets the amount of the months unit in a copy of this period.
569      * The years and days units are unaffected.
570      * <p>
571      * The months unit is not automatically normalized with the years unit.
572      * This means that a period of "15 months" is different to a period
573      * of "1 year and 3 months".
574      * <p>
575      * This instance is immutable and unaffected by this method call.
576      *
577      * @param months  the months to represent, may be negative
578      * @return a {@code Period} based on this period with the requested months, not null
579      */

580     public Period withMonths(int months) {
581         if (months == this.months) {
582             return this;
583         }
584         return create(years, months, days);
585     }
586
587     /**
588      * Returns a copy of this period with the specified amount of days.
589      * <p>
590      * This sets the amount of the days unit in a copy of this period.
591      * The years and months units are unaffected.
592      * <p>
593      * This instance is immutable and unaffected by this method call.
594      *
595      * @param days  the days to represent, may be negative
596      * @return a {@code Period} based on this period with the requested days, not null
597      */

598     public Period withDays(int days) {
599         if (days == this.days) {
600             return this;
601         }
602         return create(years, months, days);
603     }
604
605     //-----------------------------------------------------------------------
606     /**
607      * Returns a copy of this period with the specified period added.
608      * <p>
609      * This operates separately on the years, months and days.
610      * No normalization is performed.
611      * <p>
612      * For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days"
613      * returns "3 years, 8 months and 5 days".
614      * <p>
615      * The specified amount is typically an instance of {@code Period}.
616      * Other types are interpreted using {@link Period#from(TemporalAmount)}.
617      * <p>
618      * This instance is immutable and unaffected by this method call.
619      *
620      * @param amountToAdd  the amount to add, not null
621      * @return a {@code Period} based on this period with the requested period added, not null
622      * @throws DateTimeException if the specified amount has a non-ISO chronology or
623      *  contains an invalid unit
624      * @throws ArithmeticException if numeric overflow occurs
625      */

626     public Period plus(TemporalAmount amountToAdd) {
627         Period isoAmount = Period.from(amountToAdd);
628         return create(
629                 Math.addExact(years, isoAmount.years),
630                 Math.addExact(months, isoAmount.months),
631                 Math.addExact(days, isoAmount.days));
632     }
633
634     /**
635      * Returns a copy of this period with the specified years added.
636      * <p>
637      * This adds the amount to the years unit in a copy of this period.
638      * The months and days units are unaffected.
639      * For example, "1 year, 6 months and 3 days" plus 2 years returns "3 years, 6 months and 3 days".
640      * <p>
641      * This instance is immutable and unaffected by this method call.
642      *
643      * @param yearsToAdd  the years to add, positive or negative
644      * @return a {@code Period} based on this period with the specified years added, not null
645      * @throws ArithmeticException if numeric overflow occurs
646      */

647     public Period plusYears(long yearsToAdd) {
648         if (yearsToAdd == 0) {
649             return this;
650         }
651         return create(Math.toIntExact(Math.addExact(years, yearsToAdd)), months, days);
652     }
653
654     /**
655      * Returns a copy of this period with the specified months added.
656      * <p>
657      * This adds the amount to the months unit in a copy of this period.
658      * The years and days units are unaffected.
659      * For example, "1 year, 6 months and 3 days" plus 2 months returns "1 year, 8 months and 3 days".
660      * <p>
661      * This instance is immutable and unaffected by this method call.
662      *
663      * @param monthsToAdd  the months to add, positive or negative
664      * @return a {@code Period} based on this period with the specified months added, not null
665      * @throws ArithmeticException if numeric overflow occurs
666      */

667     public Period plusMonths(long monthsToAdd) {
668         if (monthsToAdd == 0) {
669             return this;
670         }
671         return create(years, Math.toIntExact(Math.addExact(months, monthsToAdd)), days);
672     }
673
674     /**
675      * Returns a copy of this period with the specified days added.
676      * <p>
677      * This adds the amount to the days unit in a copy of this period.
678      * The years and months units are unaffected.
679      * For example, "1 year, 6 months and 3 days" plus 2 days returns "1 year, 6 months and 5 days".
680      * <p>
681      * This instance is immutable and unaffected by this method call.
682      *
683      * @param daysToAdd  the days to add, positive or negative
684      * @return a {@code Period} based on this period with the specified days added, not null
685      * @throws ArithmeticException if numeric overflow occurs
686      */

687     public Period plusDays(long daysToAdd) {
688         if (daysToAdd == 0) {
689             return this;
690         }
691         return create(years, months, Math.toIntExact(Math.addExact(days, daysToAdd)));
692     }
693
694     //-----------------------------------------------------------------------
695     /**
696      * Returns a copy of this period with the specified period subtracted.
697      * <p>
698      * This operates separately on the years, months and days.
699      * No normalization is performed.
700      * <p>
701      * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days"
702      * returns "-1 years, 4 months and 1 day".
703      * <p>
704      * The specified amount is typically an instance of {@code Period}.
705      * Other types are interpreted using {@link Period#from(TemporalAmount)}.
706      * <p>
707      * This instance is immutable and unaffected by this method call.
708      *
709      * @param amountToSubtract  the amount to subtract, not null
710      * @return a {@code Period} based on this period with the requested period subtracted, not null
711      * @throws DateTimeException if the specified amount has a non-ISO chronology or
712      *  contains an invalid unit
713      * @throws ArithmeticException if numeric overflow occurs
714      */

715     public Period minus(TemporalAmount amountToSubtract) {
716         Period isoAmount = Period.from(amountToSubtract);
717         return create(
718                 Math.subtractExact(years, isoAmount.years),
719                 Math.subtractExact(months, isoAmount.months),
720                 Math.subtractExact(days, isoAmount.days));
721     }
722
723     /**
724      * Returns a copy of this period with the specified years subtracted.
725      * <p>
726      * This subtracts the amount from the years unit in a copy of this period.
727      * The months and days units are unaffected.
728      * For example, "1 year, 6 months and 3 days" minus 2 years returns "-1 years, 6 months and 3 days".
729      * <p>
730      * This instance is immutable and unaffected by this method call.
731      *
732      * @param yearsToSubtract  the years to subtract, positive or negative
733      * @return a {@code Period} based on this period with the specified years subtracted, not null
734      * @throws ArithmeticException if numeric overflow occurs
735      */

736     public Period minusYears(long yearsToSubtract) {
737         return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
738     }
739
740     /**
741      * Returns a copy of this period with the specified months subtracted.
742      * <p>
743      * This subtracts the amount from the months unit in a copy of this period.
744      * The years and days units are unaffected.
745      * For example, "1 year, 6 months and 3 days" minus 2 months returns "1 year, 4 months and 3 days".
746      * <p>
747      * This instance is immutable and unaffected by this method call.
748      *
749      * @param monthsToSubtract  the years to subtract, positive or negative
750      * @return a {@code Period} based on this period with the specified months subtracted, not null
751      * @throws ArithmeticException if numeric overflow occurs
752      */

753     public Period minusMonths(long monthsToSubtract) {
754         return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
755     }
756
757     /**
758      * Returns a copy of this period with the specified days subtracted.
759      * <p>
760      * This subtracts the amount from the days unit in a copy of this period.
761      * The years and months units are unaffected.
762      * For example, "1 year, 6 months and 3 days" minus 2 days returns "1 year, 6 months and 1 day".
763      * <p>
764      * This instance is immutable and unaffected by this method call.
765      *
766      * @param daysToSubtract  the months to subtract, positive or negative
767      * @return a {@code Period} based on this period with the specified days subtracted, not null
768      * @throws ArithmeticException if numeric overflow occurs
769      */

770     public Period minusDays(long daysToSubtract) {
771         return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
772     }
773
774     //-----------------------------------------------------------------------
775     /**
776      * Returns a new instance with each element in this period multiplied
777      * by the specified scalar.
778      * <p>
779      * This returns a period with each of the years, months and days units
780      * individually multiplied.
781      * For example, a period of "2 years, -3 months and 4 days" multiplied by
782      * 3 will return "6 years, -9 months and 12 days".
783      * No normalization is performed.
784      *
785      * @param scalar  the scalar to multiply by, not null
786      * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null
787      * @throws ArithmeticException if numeric overflow occurs
788      */

789     public Period multipliedBy(int scalar) {
790         if (this == ZERO || scalar == 1) {
791             return this;
792         }
793         return create(
794                 Math.multiplyExact(years, scalar),
795                 Math.multiplyExact(months, scalar),
796                 Math.multiplyExact(days, scalar));
797     }
798
799     /**
800      * Returns a new instance with each amount in this period negated.
801      * <p>
802      * This returns a period with each of the years, months and days units
803      * individually negated.
804      * For example, a period of "2 years, -3 months and 4 days" will be
805      * negated to "-2 years, 3 months and -4 days".
806      * No normalization is performed.
807      *
808      * @return a {@code Period} based on this period with the amounts negated, not null
809      * @throws ArithmeticException if numeric overflow occurs, which only happens if
810      *  one of the units has the value {@code Long.MIN_VALUE}
811      */

812     public Period negated() {
813         return multipliedBy(-1);
814     }
815
816     //-----------------------------------------------------------------------
817     /**
818      * Returns a copy of this period with the years and months normalized.
819      * <p>
820      * This normalizes the years and months units, leaving the days unit unchanged.
821      * The months unit is adjusted to have an absolute value less than 12,
822      * with the years unit being adjusted to compensate. For example, a period of
823      * "1 Year and 15 months" will be normalized to "2 years and 3 months".
824      * <p>
825      * The sign of the years and months units will be the same after normalization.
826      * For example, a period of "1 year and -25 months" will be normalized to
827      * "-1 year and -1 month".
828      * <p>
829      * This instance is immutable and unaffected by this method call.
830      *
831      * @return a {@code Period} based on this period with excess months normalized to years, not null
832      * @throws ArithmeticException if numeric overflow occurs
833      */

834     public Period normalized() {
835         long totalMonths = toTotalMonths();
836         long splitYears = totalMonths / 12;
837         int splitMonths = (int) (totalMonths % 12);  // no overflow
838         if (splitYears == years && splitMonths == months) {
839             return this;
840         }
841         return create(Math.toIntExact(splitYears), splitMonths, days);
842     }
843
844     /**
845      * Gets the total number of months in this period.
846      * <p>
847      * This returns the total number of months in the period by multiplying the
848      * number of years by 12 and adding the number of months.
849      * <p>
850      * This instance is immutable and unaffected by this method call.
851      *
852      * @return the total number of months in the period, may be negative
853      */

854     public long toTotalMonths() {
855         return years * 12L + months;  // no overflow
856     }
857
858     //-------------------------------------------------------------------------
859     /**
860      * Adds this period to the specified temporal object.
861      * <p>
862      * This returns a temporal object of the same observable type as the input
863      * with this period added.
864      * If the temporal has a chronology, it must be the ISO chronology.
865      * <p>
866      * In most cases, it is clearer to reverse the calling pattern by using
867      * {@link Temporal#plus(TemporalAmount)}.
868      * <pre>
869      *   // these two lines are equivalent, but the second approach is recommended
870      *   dateTime = thisPeriod.addTo(dateTime);
871      *   dateTime = dateTime.plus(thisPeriod);
872      * </pre>
873      * <p>
874      * The calculation operates as follows.
875      * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
876      * Second, if the months are zero, the years are added if non-zero, otherwise
877      * the combination of years and months is added if non-zero.
878      * Finally, any days are added.
879      * <p>
880      * This approach ensures that a partial period can be added to a partial date.
881      * For example, a period of years and/or months can be added to a {@code YearMonth},
882      * but a period including days cannot.
883      * The approach also adds years and months together when necessary, which ensures
884      * correct behaviour at the end of the month.
885      * <p>
886      * This instance is immutable and unaffected by this method call.
887      *
888      * @param temporal  the temporal object to adjust, not null
889      * @return an object of the same type with the adjustment made, not null
890      * @throws DateTimeException if unable to add
891      * @throws ArithmeticException if numeric overflow occurs
892      */

893     @Override
894     public Temporal addTo(Temporal temporal) {
895         validateChrono(temporal);
896         if (months == 0) {
897             if (years != 0) {
898                 temporal = temporal.plus(years, YEARS);
899             }
900         } else {
901             long totalMonths = toTotalMonths();
902             if (totalMonths != 0) {
903                 temporal = temporal.plus(totalMonths, MONTHS);
904             }
905         }
906         if (days != 0) {
907             temporal = temporal.plus(days, DAYS);
908         }
909         return temporal;
910     }
911
912     /**
913      * Subtracts this period from the specified temporal object.
914      * <p>
915      * This returns a temporal object of the same observable type as the input
916      * with this period subtracted.
917      * If the temporal has a chronology, it must be the ISO chronology.
918      * <p>
919      * In most cases, it is clearer to reverse the calling pattern by using
920      * {@link Temporal#minus(TemporalAmount)}.
921      * <pre>
922      *   // these two lines are equivalent, but the second approach is recommended
923      *   dateTime = thisPeriod.subtractFrom(dateTime);
924      *   dateTime = dateTime.minus(thisPeriod);
925      * </pre>
926      * <p>
927      * The calculation operates as follows.
928      * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
929      * Second, if the months are zero, the years are subtracted if non-zero, otherwise
930      * the combination of years and months is subtracted if non-zero.
931      * Finally, any days are subtracted.
932      * <p>
933      * This approach ensures that a partial period can be subtracted from a partial date.
934      * For example, a period of years and/or months can be subtracted from a {@code YearMonth},
935      * but a period including days cannot.
936      * The approach also subtracts years and months together when necessary, which ensures
937      * correct behaviour at the end of the month.
938      * <p>
939      * This instance is immutable and unaffected by this method call.
940      *
941      * @param temporal  the temporal object to adjust, not null
942      * @return an object of the same type with the adjustment made, not null
943      * @throws DateTimeException if unable to subtract
944      * @throws ArithmeticException if numeric overflow occurs
945      */

946     @Override
947     public Temporal subtractFrom(Temporal temporal) {
948         validateChrono(temporal);
949         if (months == 0) {
950             if (years != 0) {
951                 temporal = temporal.minus(years, YEARS);
952             }
953         } else {
954             long totalMonths = toTotalMonths();
955             if (totalMonths != 0) {
956                 temporal = temporal.minus(totalMonths, MONTHS);
957             }
958         }
959         if (days != 0) {
960             temporal = temporal.minus(days, DAYS);
961         }
962         return temporal;
963     }
964
965     /**
966      * Validates that the temporal has the correct chronology.
967      */

968     private void validateChrono(TemporalAccessor temporal) {
969         Objects.requireNonNull(temporal, "temporal");
970         Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
971         if (temporalChrono != null && IsoChronology.INSTANCE.equals(temporalChrono) == false) {
972             throw new DateTimeException("Chronology mismatch, expected: ISO, actual: " + temporalChrono.getId());
973         }
974     }
975
976     //-----------------------------------------------------------------------
977     /**
978      * Checks if this period is equal to another period.
979      * <p>
980      * The comparison is based on the type {@code Period} and each of the three amounts.
981      * To be equal, the years, months and days units must be individually equal.
982      * Note that this means that a period of "15 Months" is not equal to a period
983      * of "1 Year and 3 Months".
984      *
985      * @param obj  the object to check, null returns false
986      * @return true if this is equal to the other period
987      */

988     @Override
989     public boolean equals(Object obj) {
990         if (this == obj) {
991             return true;
992         }
993         if (obj instanceof Period) {
994             Period other = (Period) obj;
995             return years == other.years &&
996                     months == other.months &&
997                     days == other.days;
998         }
999         return false;
1000     }
1001
1002     /**
1003      * A hash code for this period.
1004      *
1005      * @return a suitable hash code
1006      */

1007     @Override
1008     public int hashCode() {
1009         return years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16);
1010     }
1011
1012     //-----------------------------------------------------------------------
1013     /**
1014      * Outputs this period as a {@code String}, such as {@code P6Y3M1D}.
1015      * <p>
1016      * The output will be in the ISO-8601 period format.
1017      * A zero period will be represented as zero days, 'P0D'.
1018      *
1019      * @return a string representation of this period, not null
1020      */

1021     @Override
1022     public String toString() {
1023         if (this == ZERO) {
1024             return "P0D";
1025         } else {
1026             StringBuilder buf = new StringBuilder();
1027             buf.append('P');
1028             if (years != 0) {
1029                 buf.append(years).append('Y');
1030             }
1031             if (months != 0) {
1032                 buf.append(months).append('M');
1033             }
1034             if (days != 0) {
1035                 buf.append(days).append('D');
1036             }
1037             return buf.toString();
1038         }
1039     }
1040
1041     //-----------------------------------------------------------------------
1042     /**
1043      * Writes the object using a
1044      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
1045      * @serialData
1046      * <pre>
1047      *  out.writeByte(14);  // identifies a Period
1048      *  out.writeInt(years);
1049      *  out.writeInt(months);
1050      *  out.writeInt(days);
1051      * </pre>
1052      *
1053      * @return the instance of {@code Ser}, not null
1054      */

1055     private Object writeReplace() {
1056         return new Ser(Ser.PERIOD_TYPE, this);
1057     }
1058
1059     /**
1060      * Defend against malicious streams.
1061      *
1062      * @param s the stream to read
1063      * @throws java.io.InvalidObjectException always
1064      */

1065     private void readObject(ObjectInputStream s) throws InvalidObjectException {
1066         throw new InvalidObjectException("Deserialization via serialization delegate");
1067     }
1068
1069     void writeExternal(DataOutput out) throws IOException {
1070         out.writeInt(years);
1071         out.writeInt(months);
1072         out.writeInt(days);
1073     }
1074
1075     static Period readExternal(DataInput in) throws IOException {
1076         int years = in.readInt();
1077         int months = in.readInt();
1078         int days = in.readInt();
1079         return Period.of(years, months, days);
1080     }
1081
1082 }
1083