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