Package javax.time.period

Source Code of javax.time.period.Period

/*
* Copyright (c) 2008-2009, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither the name of JSR-310 nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package javax.time.period;

import java.io.Serializable;

import javax.time.CalendricalException;
import javax.time.Duration;
import javax.time.MathUtils;
import javax.time.calendar.format.CalendricalParseException;

/**
* An immutable period consisting of the standard year, month, day, hour, minute, second and nanosecond units.
* <p>
* This is used to represent the human-scale description of an amount of time, known as a period.
* As an example, "3 months, 4 days and 7 hours" can be stored.
* <p>
* Period stores just six units - years, months, days, hours, minutes and seconds.
* Certain methods have an implied relationship between some of these units:
* <ul>
* <li>12 months in a year</li>
* <li>24 hours in a day (ignoring time zones)</li>
* <li>60 minutes in an hour</li>
* <li>60 seconds in a minute</li>
* <li>1,000,000,000 nanoseconds in a second</li>
* </ul>
* Period can be used to store data for use by any calendar system.
* However, those methods which make the assumptions above will only be valid
* for use if the calendar system matches the assumptions.
* <p>
* Note that beyond the limits specified above, the stored amounts are only descriptive.
* For example, a year in two calendar systems may differ in length.
* Only when the period is combined with a date/time in a specific calendar system can the
* duration of the period be calculated.
* <p>
* Period is immutable and thread-safe.
*
* @author Stephen Colebourne
*/
public final class Period
        implements PeriodProvider, Serializable {

    /**
     * A constant for a period of zero.
     */
    public static final Period ZERO = new Period(0, 0, 0, 0, 0, 0, 0);
    /**
     * A serialization identifier for this class.
     */
    private static final long serialVersionUID = 1L;

    /**
     * The number of years.
     */
    private final int years;
    /**
     * The number of months.
     */
    private final int months;
    /**
     * The number of days.
     */
    private final int days;
    /**
     * The number of hours.
     */
    private final int hours;
    /**
     * The number of minutes.
     */
    private final int minutes;
    /**
     * The number of seconds.
     */
    private final int seconds;
    /**
     * The number of nanoseconds.
     */
    private final long nanos;
    /**
     * The cached toString value.
     */
    private transient volatile String string;

    //-----------------------------------------------------------------------
    /**
     * Obtains an instance of <code>Period</code> from a provider of periods.
     * <p>
     * In addition to calling {@link PeriodProvider#toPeriod()} this method
     * also checks the validity of the result of the provider.
     *
     * @param periodProvider  a provider of period information, not null
     * @return the created period instance, never null
     */
    public static Period period(PeriodProvider periodProvider) {
        if (periodProvider == null) {
            throw new NullPointerException("Period provider must not be null");
        }
        Period provided = periodProvider.toPeriod();
        if (provided == null) {
            throw new NullPointerException("The implementation of PeriodProvider must not return null");
        }
        return provided;
    }

    /**
     * Obtains an instance of <code>Period</code> from amounts from years to seconds.
     *
     * @param years  the amount of years
     * @param months  the amount of months
     * @param days  the amount of days
     * @param hours  the amount of hours
     * @param minutes  the amount of minutes
     * @param seconds  the amount of seconds
     * @return the created period instance, never null
     */
    public static Period period(int years, int months, int days, int hours, int minutes, int seconds) {
        if ((years | months | days | hours | minutes | seconds) == 0) {
            return ZERO;
        }
        return new Period(years, months, days, hours, minutes, seconds, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from amounts from years to nanoseconds.
     *
     * @param years  the amount of years
     * @param months  the amount of months
     * @param days  the amount of days
     * @param hours  the amount of hours
     * @param minutes  the amount of minutes
     * @param seconds  the amount of seconds
     * @param nanos  the amount of nanos
     * @return the created period instance, never null
     */
    public static Period period(int years, int months, int days, int hours, int minutes, int seconds, long nanos) {
        if ((years | months | days | hours | minutes | seconds | nanos) == 0) {
            return ZERO;
        }
        return new Period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Obtains an instance of <code>Period</code> from years, months and days.
     *
     * @param years  the amount of years
     * @param months  the amount of months
     * @return the created period instance, never null
     */
    public static Period yearsMonths(int years, int months) {
        if ((years | months) == 0) {
            return ZERO;
        }
        return new Period(years, months, 0, 0, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from years, months and days.
     *
     * @param years  the amount of years
     * @param months  the amount of months
     * @param days  the amount of days
     * @return the created period instance, never null
     */
    public static Period yearsMonthsDays(int years, int months, int days) {
        if ((years | months | days) == 0) {
            return ZERO;
        }
        return new Period(years, months, days, 0, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from hours, minutes and seconds.
     *
     * @param hours  the amount of hours
     * @param minutes  the amount of minutes
     * @param seconds  the amount of seconds
     * @return the created period instance, never null
     */
    public static Period hoursMinutesSeconds(int hours, int minutes, int seconds) {
        if ((hours | minutes | seconds) == 0) {
            return ZERO;
        }
        return new Period(0, 0, 0, hours, minutes, seconds, 0);
    }

    //-----------------------------------------------------------------------
    /**
     * Obtains an instance of <code>Period</code> from a number of years.
     *
     * @param years  the amount of years
     * @return the created period instance, never null
     */
    public static Period years(int years) {
        if (years == 0) {
            return ZERO;
        }
        return new Period(years, 0, 0, 0, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of months.
     *
     * @param months  the amount of months
     * @return the created period instance, never null
     */
    public static Period months(int months) {
        if (months == 0) {
            return ZERO;
        }
        return new Period(0, months, 0, 0, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of days.
     *
     * @param days  the amount of days
     * @return the created period instance, never null
     */
    public static Period days(int days) {
        if (days == 0) {
            return ZERO;
        }
        return new Period(0, 0, days, 0, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of hours.
     *
     * @param hours  the amount of hours
     * @return the created period instance, never null
     */
    public static Period hours(int hours) {
        if (hours == 0) {
            return ZERO;
        }
        return new Period(0, 0, 0, hours, 0, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of minutes.
     *
     * @param minutes  the amount of minutes
     * @return the created period instance, never null
     */
    public static Period minutes(int minutes) {
        if (minutes == 0) {
            return ZERO;
        }
        return new Period(0, 0, 0, 0, minutes, 0, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of seconds.
     *
     * @param seconds  the amount of seconds
     * @return the created period instance, never null
     */
    public static Period seconds(int seconds) {
        if (seconds == 0) {
            return ZERO;
        }
        return new Period(0, 0, 0, 0, 0, seconds, 0);
    }

    /**
     * Obtains an instance of <code>Period</code> from a number of nanoseconds.
     *
     * @param nanos  the amount of nanos
     * @return the created period instance, never null
     */
    public static Period nanos(long nanos) {
        if (nanos == 0) {
            return ZERO;
        }
        return new Period(0, 0, 0, 0, 0, 0, nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Obtains an instance of <code>Period</code> from a string formatted as <code>PnYnMnDTnHnMn.nS</code>.
     * <p>
     * This will parse the string produced by <code>toString()</code> which is
     * a subset of the ISO8601 period format <code>PnYnMnDTnHnMn.nS</code>.
     * <p>
     * The string consists of a series of numbers with a suffix identifying their meaning.
     * The values, and suffixes, must be in the sequence year, month, day, hour, minute, second.
     * Any of the number/suffix pairs may be omitted providing at least one is present.
     * If the period is zero, the value is normally represented as <code>PT0S</code>.
     * The numbers must consist of ASCII digits.
     * Any of the numbers may be negative. Negative zero is not accepted.
     * The number of nanoseconds is expressed as an optional fraction of the seconds.
     * There must be at least one digit before any decimal point.
     * There must be between 1 and 9 inclusive digits after any decimal point.
     * The letters will all be accepted in upper or lower case.
     * The decimal point may be either a dot or a comma.
     *
     * @param text  the text to parse, not null
     * @return the created Period, never null
     * @throws CalendricalParseException if the text cannot be parsed to a Period
     */
    public static Period parse(final String text) {
        PeriodFields.checkNotNull(text, "Text to parse must not be null");
        return PeriodParser.getInstance().parse(text);
    }

    //-----------------------------------------------------------------------
    /**
     * Constructor.
     *
     * @param years  the amount
     * @param months  the amount
     * @param days  the amount
     * @param hours  the amount
     * @param minutes  the amount
     * @param seconds  the amount
     * @param nanos  the amount
     */
    private Period(int years, int months, int days, int hours, int minutes, int seconds, long nanos) {
        this.years = years;
        this.months = months;
        this.days = days;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
        this.nanos = nanos;
    }

    /**
     * Resolves singletons.
     *
     * @return the resolved instance
     */
    private Object readResolve() {
        if ((years | months | days | hours | minutes | seconds | nanos) == 0) {
            return ZERO;
        }
        return this;
    }

    //-----------------------------------------------------------------------
    /**
     * Checks if the period is zero-length.
     *
     * @return true if this period is zero-length
     */
    public boolean isZero() {
        return (this == ZERO);
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the amount of years of the overall period, if any.
     *
     * @return the amount of years of the overall period
     */
    public int getYears() {
        return years;
    }

    /**
     * Gets the amount of months of the overall period, if any.
     *
     * @return the amount of months of the overall period
     */
    public int getMonths() {
        return months;
    }

    /**
     * Gets the amount of days of the overall period, if any.
     *
     * @return the amount of days of the overall period
     */
    public int getDays() {
        return days;
    }

    /**
     * Gets the amount of hours of the overall period, if any.
     *
     * @return the amount of hours of the overall period
     */
    public int getHours() {
        return hours;
    }

    /**
     * Gets the amount of minutes of the overall period, if any.
     *
     * @return the amount of minutes of the overall period
     */
    public int getMinutes() {
        return minutes;
    }

    /**
     * Gets the amount of seconds of the overall period, if any.
     *
     * @return the amount of seconds of the overall period
     */
    public int getSeconds() {
        return seconds;
    }

    /**
     * Gets the amount of nanoseconds of the overall period, if any.
     *
     * @return the amount of nanoseconds of the overall period
     */
    public long getNanos() {
        return nanos;
    }

    /**
     * Gets the amount of nanoseconds of the overall period safely converted
     * to an <code>int</code>.
     *
     * @return the amount of nanoseconds of the overall period
     * @throws ArithmeticException if the number of nanoseconds exceeds the capacity of an int
     */
    public int getNanosInt() {
        return MathUtils.safeToInt(nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with the specified amount of years.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param years  the years to represent
     * @return a new updated period instance, never null
     */
    public Period withYears(int years) {
        if (years == this.years) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of months.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param months  the months to represent
     * @return a new updated period instance, never null
     */
    public Period withMonths(int months) {
        if (months == this.months) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of days.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param days  the days to represent
     * @return a new updated period instance, never null
     */
    public Period withDays(int days) {
        if (days == this.days) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of hours.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param hours  the hours to represent
     * @return a new updated period instance, never null
     */
    public Period withHours(int hours) {
        if (hours == this.hours) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of minutes.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param minutes  the minutes to represent
     * @return a new updated period instance, never null
     */
    public Period withMinutes(int minutes) {
        if (minutes == this.minutes) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of seconds.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param seconds  the seconds to represent
     * @return a new updated period instance, never null
     */
    public Period withSeconds(int seconds) {
        if (seconds == this.seconds) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with the specified amount of nanoseconds.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param nanos  the nanoseconds to represent
     * @return a new updated period instance, never null
     */
    public Period withNanos(long nanos) {
        if (nanos == this.nanos) {
            return this;
        }
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with the specified period added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param periodProvider  the period to add, not null
     * @return a new updated period instance, never null
     * @throws NullPointerException if the period to add is null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plus(PeriodProvider periodProvider) {
        Period other = period(periodProvider);
        return period(
                MathUtils.safeAdd(years, other.years),
                MathUtils.safeAdd(months, other.months),
                MathUtils.safeAdd(days, other.days),
                MathUtils.safeAdd(hours, other.hours),
                MathUtils.safeAdd(minutes, other.minutes),
                MathUtils.safeAdd(seconds, other.seconds),
                MathUtils.safeAdd(nanos, other.nanos));
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with the specified number of years added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param years  the years to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusYears(int years) {
        return withYears(MathUtils.safeAdd(this.years, years));
    }

    /**
     * Returns a copy of this period with the specified number of months added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param months  the months to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusMonths(int months) {
        return withMonths(MathUtils.safeAdd(this.months, months));
    }

    /**
     * Returns a copy of this period with the specified number of days added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param days  the days to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusDays(int days) {
        return withDays(MathUtils.safeAdd(this.days, days));
    }

    /**
     * Returns a copy of this period with the specified number of hours added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param hours  the hours to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusHours(int hours) {
        return withHours(MathUtils.safeAdd(this.hours, hours));
    }

    /**
     * Returns a copy of this period with the specified number of minutes added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param minutes  the minutes to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusMinutes(int minutes) {
        return withMinutes(MathUtils.safeAdd(this.minutes, minutes));
    }

    /**
     * Returns a copy of this period with the specified number of seconds added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param seconds  the seconds to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusSeconds(int seconds) {
        return withSeconds(MathUtils.safeAdd(this.seconds, seconds));
    }

    /**
     * Returns a copy of this period with the specified number of nanoseconds added.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param nanos  the nanoseconds to add, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period plusNanos(long nanos) {
        return withNanos(MathUtils.safeAdd(this.nanos, nanos));
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with the specified period subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param periodProvider  the period to subtract, not null
     * @return a new updated period instance, never null
     * @throws NullPointerException if the period to subtract is null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minus(PeriodProvider periodProvider) {
        Period other = period(periodProvider);
        return period(
                MathUtils.safeSubtract(years, other.years),
                MathUtils.safeSubtract(months, other.months),
                MathUtils.safeSubtract(days, other.days),
                MathUtils.safeSubtract(hours, other.hours),
                MathUtils.safeSubtract(minutes, other.minutes),
                MathUtils.safeSubtract(seconds, other.seconds),
                MathUtils.safeSubtract(nanos, other.nanos));
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with the specified number of years subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param years  the years to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusYears(int years) {
        return withYears(MathUtils.safeSubtract(this.years, years));
    }

    /**
     * Returns a copy of this period with the specified number of months subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param months  the months to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusMonths(int months) {
        return withMonths(MathUtils.safeSubtract(this.months, months));
    }

    /**
     * Returns a copy of this period with the specified number of days subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param days  the days to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusDays(int days) {
        return withDays(MathUtils.safeSubtract(this.days, days));
    }

    /**
     * Returns a copy of this period with the specified number of hours subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param hours  the hours to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusHours(int hours) {
        return withHours(MathUtils.safeSubtract(this.hours, hours));
    }

    /**
     * Returns a copy of this period with the specified number of minutes subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param minutes  the minutes to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusMinutes(int minutes) {
        return withMinutes(MathUtils.safeSubtract(this.minutes, minutes));
    }

    /**
     * Returns a copy of this period with the specified number of seconds subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param seconds  the seconds to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusSeconds(int seconds) {
        return withSeconds(MathUtils.safeSubtract(this.seconds, seconds));
    }

    /**
     * Returns a copy of this period with the specified number of nanoseconds subtracted.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @param nanos  the nanoseconds to subtract, positive or negative
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period minusNanos(long nanos) {
        return withNanos(MathUtils.safeSubtract(this.nanos, nanos));
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a new instance with each element in this period multiplied
     * by the specified scalar.
     *
     * @param scalar  the scalar to multiply by, not null
     * @return the new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period multipliedBy(int scalar) {
        if (this == ZERO || scalar == 1) {
            return this;
        }
        return period(
                MathUtils.safeMultiply(years, scalar),
                MathUtils.safeMultiply(months, scalar),
                MathUtils.safeMultiply(days, scalar),
                MathUtils.safeMultiply(hours, scalar),
                MathUtils.safeMultiply(minutes, scalar),
                MathUtils.safeMultiply(seconds, scalar),
                MathUtils.safeMultiply(nanos, scalar));
    }

    /**
     * Returns a new instance with each element in this period divided
     * by the specified value.
     * <p>
     * The implementation simply divides each separate field by the divisor
     * using integer division.
     *
     * @param divisor  the value to divide by, not null
     * @return the new updated period instance, never null
     * @throws ArithmeticException if dividing by zero
     */
    public Period dividedBy(int divisor) {
        if (divisor == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        if (this == ZERO || divisor == 1) {
            return this;
        }
        return period(
                years / divisor, months / divisor, days / divisor,
                hours / divisor, minutes / divisor, seconds / divisor, nanos / divisor);
    }

    /**
     * Returns a new instance with each amount in this period negated.
     *
     * @return the new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period negated() {
        return multipliedBy(-1);
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a copy of this period with all amounts normalized to the
     * standard ranges for date-time fields.
     * <p>
     * Two normalizations occur, one for years and months, and one for
     * hours, minutes, seconds and nanoseconds.
     * Days are not normalized, as a day may vary in length at daylight savings cutover.
     * For example, a period of P1Y15M1DT28H61M will be normalized to P2Y3M1DT29H1M.
     * <p>
     * Note that this method normalizes using assumptions:
     * <ul>
     * <li>12 months in a year</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period normalized() {
        if (this == ZERO) {
            return ZERO;
        }
        int years = this.years;
        int months = this.months;
        if (months >= 12) {
            years = MathUtils.safeAdd(years, months / 12);
            months = months % 12;
        }
        long total = (hours * 60L * 60L) + (minutes * 60L) + seconds;  // will not overflow
        total = MathUtils.safeMultiply(total, 1000000000);
        total = MathUtils.safeAdd(total, nanos);
        long nanos = total % 1000000000L;
        total /= 1000000000L;
        int seconds = (int) (total % 60);
        total /= 60;
        int minutes = (int) (total % 60);
        total /= 60;
        int hours = MathUtils.safeToInt(total);
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    /**
     * Returns a copy of this period with all amounts normalized to the
     * standard ranges for date-time fields including the assumption that
     * days are 24 hours long.
     * <p>
     * Two normalizations occur, one for years and months, and one for
     * days, hours, minutes, seconds and nanoseconds.
     * For example, a period of P1Y15M1DT28H will be normalized to P2Y3M2DT4H.
     * <p>
     * Note that this method normalizes using assumptions:
     * <ul>
     * <li>12 months in a year</li>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     * <p>
     * This instance is immutable and unaffected by this method call.
     *
     * @return a new updated period instance, never null
     * @throws ArithmeticException if the calculation result overflows
     */
    public Period normalizedWith24HourDays() {
        if (this == ZERO) {
            return ZERO;
        }
        int years = this.years;
        int months = this.months;
        if (months >= 12) {
            years = MathUtils.safeAdd(years, months / 12);
            months = months % 12;
        }
        long total = (days * 24L * 60L * 60L) +
                        (hours * 60L * 60L) +
                        (minutes * 60L) + seconds;  // will not overflow
        total = MathUtils.safeMultiply(total, 1000000000);
        total = MathUtils.safeAdd(total, nanos);
        long nanos = total % 1000000000L;
        total /= 1000000000L;
        int seconds = (int) (total % 60);
        total /= 60;
        int minutes = (int) (total % 60);
        total /= 60;
        int hours = (int) (total % 24);
        total /= 24;
        int days = MathUtils.safeToInt(total);
        return period(years, months, days, hours, minutes, seconds, nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of years represented by this period using standard
     * assumptions for the meaning of month.
     * <p>
     * This method ignores days, hours, minutes, seconds and nanos.
     * It calculates using the assumption:
     * <ul>
     * <li>12 months in a year</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of years
     */
    public long totalYears() {
        return ((long) years) + ((long) months) / 12L;
    }

    /**
     * Gets the total number of months represented by this period using standard
     * assumptions for the meaning of month.
     * <p>
     * This method ignores days, hours, minutes, seconds and nanos.
     * It calculates using the assumption:
     * <ul>
     * <li>12 months in a year</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of years
     */
    public long totalMonths() {
        return ((long) years) * 12L + ((long) months);
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of days represented by this period using standard
     * assumptions for the meaning of day, hour, minute and second.
     * <p>
     * This method ignores years and months.
     * It calculates using assumptions:
     * <ul>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of days
     */
    public long totalDaysWith24HourDays() {
        if (this == ZERO) {
            return 0;
        }
        return days + (hours + (minutes + (seconds + (nanos / 1000000000L)) / 60L) / 60L) / 24L// will not overflow
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of hours represented by this period using standard
     * assumptions for the meaning of hour, minute and second.
     * <p>
     * This method ignores years, months and days.
     * It calculates using assumptions:
     * <ul>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of hours
     */
    public long totalHours() {
        if (this == ZERO) {
            return 0;
        }
        return hours + (minutes + (seconds + (nanos / 1000000000L)) / 60L) / 60L// will not overflow
    }

    /**
     * Gets the total number of hours represented by this period using standard
     * assumptions for the meaning of day, hour, minute and second.
     * <p>
     * This method ignores years and months.
     * It calculates using assumptions:
     * <ul>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of hours
     */
    public long totalHoursWith24HourDays() {
        if (this == ZERO) {
            return 0;
        }
        return days * 24L + hours + (minutes + (seconds + (nanos / 1000000000L)) / 60L) / 60L// will not overflow
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of minutes represented by this period using standard
     * assumptions for the meaning of hour, minute and second.
     * <p>
     * This method ignores years, months and days.
     * It calculates using assumptions:
     * <ul>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of minutes
     */
    public long totalMinutes() {
        if (this == ZERO) {
            return 0;
        }
        return hours * 60L + minutes + (seconds + (nanos / 1000000000L)) / 60L// will not overflow
    }

    /**
     * Gets the total number of minutes represented by this period using standard
     * assumptions for the meaning of day, hour, minute and second.
     * <p>
     * This method ignores years and months.
     * It calculates using assumptions:
     * <ul>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of minutes
     */
    public long totalMinutesWith24HourDays() {
        if (this == ZERO) {
            return 0;
        }
        return (days * 24L + hours) * 60L + minutes + (seconds + (nanos / 1000000000L)) / 60L// will not overflow
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of seconds represented by this period using standard
     * assumptions for the meaning of hour, minute and second.
     * <p>
     * This method ignores years, months and days.
     * It calculates using assumptions:
     * <ul>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of seconds
     */
    public long totalSeconds() {
        if (this == ZERO) {
            return 0;
        }
        return (hours * 60L + minutes) * 60L + seconds + nanos / 1000000000L// will not overflow
    }

    /**
     * Gets the total number of seconds represented by this period using standard
     * assumptions for the meaning of day, hour, minute and second.
     * <p>
     * This method ignores years and months.
     * It calculates using assumptions:
     * <ul>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of seconds
     */
    public long totalSecondsWith24HourDays() {
        if (this == ZERO) {
            return 0;
        }
        return ((days * 24L + hours) * 60L + minutes) * 60L + seconds + nanos / 1000000000L// will not overflow
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the total number of nanoseconds represented by this period using standard
     * assumptions for the meaning of hour, minute and second.
     * <p>
     * This method ignores years, months and days.
     * It calculates using assumptions:
     * <ul>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of nanoseconds
     * @throws ArithmeticException if the calculation result overflows
     */
    public long totalNanos() {
        if (this == ZERO) {
            return 0;
        }
        long secs = ((hours * 60L + minutes) * 60L + seconds)// will not overflow
        long otherNanos = MathUtils.safeMultiply(secs, 1000000000L);
        return MathUtils.safeAdd(otherNanos, nanos);
    }

    /**
     * Gets the total number of nanoseconds represented by this period using standard
     * assumptions for the meaning of day, hour, minute and second.
     * <p>
     * This method ignores years and months.
     * It calculates using assumptions:
     * <ul>
     * <li>24 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return the total number of nanoseconds
     * @throws ArithmeticException if the calculation result overflows
     */
    public long totalNanosWith24HourDays() {
        if (this == ZERO) {
            return 0;
        }
        long secs = (((days * 24L + hours) * 60L + minutes) * 60L + seconds)// will not overflow
        long otherNanos = MathUtils.safeMultiply(secs, 1000000000L);
        return MathUtils.safeAdd(otherNanos, nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Converts this object to a <code>Period</code>, trivially returning <code>this</code>.
     *
     * @return <code>this</code>, never null
     */
    public Period toPeriod() {
        return this;
    }

    /**
     * Converts this object to a <code>PeriodFields</code> instance.
     * <p>
     * The resulting period is always normalized such that it does not contain
     * zero amounts.
     *
     * @return an equivalent period fields instance, never null
     */
    public PeriodFields toPeriodFields() {
        // TODO: Maybe remove?
        return PeriodFields.periodFields(this);
    }

    //-----------------------------------------------------------------------
    /**
     * Converts this object to a <code>Duration</code> using the hours, minutes,
     * seconds and nanoseconds fields.
     * If years, months or days are present an exception is thrown.
     * <p>
     * The duration is calculated using assumptions:
     * <ul>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return <code>this</code>, never null
     * @throws CalendricalException if the period cannot be converted as it contains years/months/days
     */
    public Duration toDuration() {
        if ((years | months | days) > 0) {
            throw new CalendricalException("Unable to convert period to duration as years/months/days are present: " + this);
        }
        long secs = (hours * 60L + minutes) * 60L + seconds;  // will not overflow
        return Duration.seconds(secs, nanos);
    }

    /**
     * Converts this object to a <code>Duration</code> using the days, hours, minutes,
     * seconds and nanoseconds fields.
     * If years or months are present an exception is thrown.
     * <p>
     * The duration is calculated using assumptions:
     * <ul>
     * <li>60 hours in a day</li>
     * <li>60 minutes in an hour</li>
     * <li>60 seconds in a minute</li>
     * <li>1,000,000,000 nanoseconds in a second</li>
     * </ul>
     * This method is only appropriate to call if these assumptions are met.
     *
     * @return <code>this</code>, never null
     * @throws CalendricalException if the period cannot be converted as it contains years/months/days
     */
    public Duration toDurationWith24HourDays() {
        if ((years | months) > 0) {
            throw new CalendricalException("Unable to convert period to duration as years/months are present: " + this);
        }
        long secs = ((days * 24L + hours) * 60L + minutes) * 60L + seconds;  // will not overflow
        return Duration.seconds(secs, nanos);
    }

    //-----------------------------------------------------------------------
    /**
     * Is this period equal to the specified period.
     *
     * @param obj  the other period to compare to, null returns false
     * @return true if this instance is equal to the specified period
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof Period) {
            Period other = (Period) obj;
            return years == other.years && months == other.months && days == other.days &
                    hours == other.hours && minutes == other.minutes &&
                    seconds == other.seconds && nanos == other.nanos;
        }
        return false;
    }

    /**
     * Returns the hash code for this period.
     *
     * @return a suitable hash code
     */
    @Override
    public int hashCode() {
        // SPEC: Require unique hash code for all periods where fields within these inclusive bounds:
        // years 0-31, months 0-11, days 0-31, hours 0-23, minutes 0-59, seconds 0-59
        // IMPL: Ordered such that overflow from one field doesn't immediately affect the next field
        // years 5 bits, months 4 bits, days 6 bits, hours 5 bits, minutes 6 bits, seconds 6 bits
        return ((years << 27) | (years >>> 5)) ^
                ((hours << 22) | (hours >>> 10)) ^
                ((months << 18) | (months >>> 14)) ^
                ((minutes << 12) | (minutes >>> 20)) ^
                ((days << 6) | (days >>> 26)) ^ seconds ^ (((int) nanos) + 37);
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a string representation of the amount of time.
     *
     * @return the amount of time in ISO8601 string format
     */
    @Override
    public String toString() {
        String str = string;
        if (str == null) {
            if (this == ZERO) {
                str = "PT0S";
            } else {
                StringBuilder buf = new StringBuilder();
                buf.append('P');
                if (years != 0) {
                    buf.append(years).append('Y');
                }
                if (months != 0) {
                    buf.append(months).append('M');
                }
                if (days != 0) {
                    buf.append(days).append('D');
                }
                if ((hours | minutes | seconds) != 0 || nanos != 0) {
                    buf.append('T');
                    if (hours != 0) {
                        buf.append(hours).append('H');
                    }
                    if (minutes != 0) {
                        buf.append(minutes).append('M');
                    }
                    if (seconds != 0 || nanos != 0) {
                        if (nanos == 0) {
                            buf.append(seconds).append('S');
                        } else {
                            long s = seconds + (nanos / 1000000000);
                            long n = nanos % 1000000000;
                            if (s < 0 && n > 0) {
                                n -= 1000000000;
                                s++;
                            } else if (s > 0 && n < 0) {
                                n += 1000000000;
                                s--;
                            }
                            if (n < 0) {
                                n = -n;
                                if (s == 0) {
                                    buf.append('-');
                                }
                            }
                            buf.append(s).append('.').append(n);
                            while (buf.charAt(buf.length() - 1) == '0') {
                                buf.setLength(buf.length() - 1);
                            }
                            buf.append('S');
                        }
                    }
                }
                str = buf.toString();
            }
            string = str;
        }
        return str;
    }

}
TOP

Related Classes of javax.time.period.Period

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.