1/*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * This file is available under and governed by the GNU General Public
28 * License version 2 only, as published by the Free Software Foundation.
29 * However, the following notice accompanied the original version of this
30 * file:
31 *
32 * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
33 *
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions are met:
38 *
39 *  * Redistributions of source code must retain the above copyright notice,
40 *    this list of conditions and the following disclaimer.
41 *
42 *  * Redistributions in binary form must reproduce the above copyright notice,
43 *    this list of conditions and the following disclaimer in the documentation
44 *    and/or other materials provided with the distribution.
45 *
46 *  * Neither the name of JSR-310 nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 */
62package java.time.chrono;
63
64import java.time.DateTimeException;
65import java.time.temporal.ChronoUnit;
66import java.time.temporal.Temporal;
67import java.time.temporal.TemporalAmount;
68import java.time.temporal.TemporalUnit;
69import java.time.temporal.UnsupportedTemporalTypeException;
70import java.util.List;
71import java.util.Objects;
72
73/**
74 * A date-based amount of time, such as '3 years, 4 months and 5 days' in an
75 * arbitrary chronology, intended for advanced globalization use cases.
76 * <p>
77 * This interface models a date-based amount of time in a calendar system.
78 * While most calendar systems use years, months and days, some do not.
79 * Therefore, this interface operates solely in terms of a set of supported
80 * units that are defined by the {@code Chronology}.
81 * The set of supported units is fixed for a given chronology.
82 * The amount of a supported unit may be set to zero.
83 * <p>
84 * The period is modeled as a directed amount of time, meaning that individual
85 * parts of the period may be negative.
86 *
87 * @implSpec
88 * This interface must be implemented with care to ensure other classes operate correctly.
89 * All implementations that can be instantiated must be final, immutable and thread-safe.
90 * Subclasses should be Serializable wherever possible.
91 *
92 * @since 1.8
93 */
94public interface ChronoPeriod
95        extends TemporalAmount {
96
97    /**
98     * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates.
99     * <p>
100     * The start date is included, but the end date is not.
101     * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}.
102     * As such, the calculation is chronology specific.
103     * <p>
104     * The chronology of the first date is used.
105     * The chronology of the second date is ignored, with the date being converted
106     * to the target chronology system before the calculation starts.
107     * <p>
108     * The result of this method can be a negative period if the end is before the start.
109     * In most cases, the positive/negative sign will be the same in each of the supported fields.
110     *
111     * @param startDateInclusive  the start date, inclusive, specifying the chronology of the calculation, not null
112     * @param endDateExclusive  the end date, exclusive, in any chronology, not null
113     * @return the period between this date and the end date, not null
114     * @see ChronoLocalDate#until(ChronoLocalDate)
115     */
116    public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) {
117        Objects.requireNonNull(startDateInclusive, "startDateInclusive");
118        Objects.requireNonNull(endDateExclusive, "endDateExclusive");
119        return startDateInclusive.until(endDateExclusive);
120    }
121
122    //-----------------------------------------------------------------------
123    /**
124     * Gets the value of the requested unit.
125     * <p>
126     * The supported units are chronology specific.
127     * They will typically be {@link ChronoUnit#YEARS YEARS},
128     * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
129     * Requesting an unsupported unit will throw an exception.
130     *
131     * @param unit the {@code TemporalUnit} for which to return the value
132     * @return the long value of the unit
133     * @throws DateTimeException if the unit is not supported
134     * @throws UnsupportedTemporalTypeException if the unit is not supported
135     */
136    @Override
137    long get(TemporalUnit unit);
138
139    /**
140     * Gets the set of units supported by this period.
141     * <p>
142     * The supported units are chronology specific.
143     * They will typically be {@link ChronoUnit#YEARS YEARS},
144     * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
145     * They are returned in order from largest to smallest.
146     * <p>
147     * This set can be used in conjunction with {@link #get(TemporalUnit)}
148     * to access the entire state of the period.
149     *
150     * @return a list containing the supported units, not null
151     */
152    @Override
153    List<TemporalUnit> getUnits();
154
155    /**
156     * Gets the chronology that defines the meaning of the supported units.
157     * <p>
158     * The period is defined by the chronology.
159     * It controls the supported units and restricts addition/subtraction
160     * to {@code ChronoLocalDate} instances of the same chronology.
161     *
162     * @return the chronology defining the period, not null
163     */
164    Chronology getChronology();
165
166    //-----------------------------------------------------------------------
167    /**
168     * Checks if all the supported units of this period are zero.
169     *
170     * @return true if this period is zero-length
171     */
172    default boolean isZero() {
173        for (TemporalUnit unit : getUnits()) {
174            if (get(unit) != 0) {
175                return false;
176            }
177        }
178        return true;
179    }
180
181    /**
182     * Checks if any of the supported units of this period are negative.
183     *
184     * @return true if any unit of this period is negative
185     */
186    default boolean isNegative() {
187        for (TemporalUnit unit : getUnits()) {
188            if (get(unit) < 0) {
189                return true;
190            }
191        }
192        return false;
193    }
194
195    //-----------------------------------------------------------------------
196    /**
197     * Returns a copy of this period with the specified period added.
198     * <p>
199     * If the specified amount is a {@code ChronoPeriod} then it must have
200     * the same chronology as this period. Implementations may choose to
201     * accept or reject other {@code TemporalAmount} implementations.
202     * <p>
203     * This instance is immutable and unaffected by this method call.
204     *
205     * @param amountToAdd  the period to add, not null
206     * @return a {@code ChronoPeriod} based on this period with the requested period added, not null
207     * @throws ArithmeticException if numeric overflow occurs
208     */
209    ChronoPeriod plus(TemporalAmount amountToAdd);
210
211    /**
212     * Returns a copy of this period with the specified period subtracted.
213     * <p>
214     * If the specified amount is a {@code ChronoPeriod} then it must have
215     * the same chronology as this period. Implementations may choose to
216     * accept or reject other {@code TemporalAmount} implementations.
217     * <p>
218     * This instance is immutable and unaffected by this method call.
219     *
220     * @param amountToSubtract  the period to subtract, not null
221     * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null
222     * @throws ArithmeticException if numeric overflow occurs
223     */
224    ChronoPeriod minus(TemporalAmount amountToSubtract);
225
226    //-----------------------------------------------------------------------
227    /**
228     * Returns a new instance with each amount in this period in this period
229     * multiplied by the specified scalar.
230     * <p>
231     * This returns a period with each supported unit individually multiplied.
232     * For example, a period of "2 years, -3 months and 4 days" multiplied by
233     * 3 will return "6 years, -9 months and 12 days".
234     * No normalization is performed.
235     *
236     * @param scalar  the scalar to multiply by, not null
237     * @return a {@code ChronoPeriod} based on this period with the amounts multiplied
238     *  by the scalar, not null
239     * @throws ArithmeticException if numeric overflow occurs
240     */
241    ChronoPeriod multipliedBy(int scalar);
242
243    /**
244     * Returns a new instance with each amount in this period negated.
245     * <p>
246     * This returns a period with each supported unit individually negated.
247     * For example, a period of "2 years, -3 months and 4 days" will be
248     * negated to "-2 years, 3 months and -4 days".
249     * No normalization is performed.
250     *
251     * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null
252     * @throws ArithmeticException if numeric overflow occurs, which only happens if
253     *  one of the units has the value {@code Long.MIN_VALUE}
254     */
255    default ChronoPeriod negated() {
256        return multipliedBy(-1);
257    }
258
259    //-----------------------------------------------------------------------
260    /**
261     * Returns a copy of this period with the amounts of each unit normalized.
262     * <p>
263     * The process of normalization is specific to each calendar system.
264     * For example, in the ISO calendar system, the years and months are
265     * normalized but the days are not, such that "15 months" would be
266     * normalized to "1 year and 3 months".
267     * <p>
268     * This instance is immutable and unaffected by this method call.
269     *
270     * @return a {@code ChronoPeriod} based on this period with the amounts of each
271     *  unit normalized, not null
272     * @throws ArithmeticException if numeric overflow occurs
273     */
274    ChronoPeriod normalized();
275
276    //-------------------------------------------------------------------------
277    /**
278     * Adds this period to the specified temporal object.
279     * <p>
280     * This returns a temporal object of the same observable type as the input
281     * with this period added.
282     * <p>
283     * In most cases, it is clearer to reverse the calling pattern by using
284     * {@link Temporal#plus(TemporalAmount)}.
285     * <pre>
286     *   // these two lines are equivalent, but the second approach is recommended
287     *   dateTime = thisPeriod.addTo(dateTime);
288     *   dateTime = dateTime.plus(thisPeriod);
289     * </pre>
290     * <p>
291     * The specified temporal must have the same chronology as this period.
292     * This returns a temporal with the non-zero supported units added.
293     * <p>
294     * This instance is immutable and unaffected by this method call.
295     *
296     * @param temporal  the temporal object to adjust, not null
297     * @return an object of the same type with the adjustment made, not null
298     * @throws DateTimeException if unable to add
299     * @throws ArithmeticException if numeric overflow occurs
300     */
301    @Override
302    Temporal addTo(Temporal temporal);
303
304    /**
305     * Subtracts this period from the specified temporal object.
306     * <p>
307     * This returns a temporal object of the same observable type as the input
308     * with this period subtracted.
309     * <p>
310     * In most cases, it is clearer to reverse the calling pattern by using
311     * {@link Temporal#minus(TemporalAmount)}.
312     * <pre>
313     *   // these two lines are equivalent, but the second approach is recommended
314     *   dateTime = thisPeriod.subtractFrom(dateTime);
315     *   dateTime = dateTime.minus(thisPeriod);
316     * </pre>
317     * <p>
318     * The specified temporal must have the same chronology as this period.
319     * This returns a temporal with the non-zero supported units subtracted.
320     * <p>
321     * This instance is immutable and unaffected by this method call.
322     *
323     * @param temporal  the temporal object to adjust, not null
324     * @return an object of the same type with the adjustment made, not null
325     * @throws DateTimeException if unable to subtract
326     * @throws ArithmeticException if numeric overflow occurs
327     */
328    @Override
329    Temporal subtractFrom(Temporal temporal);
330
331    //-----------------------------------------------------------------------
332    /**
333     * Checks if this period is equal to another period, including the chronology.
334     * <p>
335     * Compares this period with another ensuring that the type, each amount and
336     * the chronology are the same.
337     * Note that this means that a period of "15 Months" is not equal to a period
338     * of "1 Year and 3 Months".
339     *
340     * @param obj  the object to check, null returns false
341     * @return true if this is equal to the other period
342     */
343    @Override
344    boolean equals(Object obj);
345
346    /**
347     * A hash code for this period.
348     *
349     * @return a suitable hash code
350     */
351    @Override
352    int hashCode();
353
354    //-----------------------------------------------------------------------
355    /**
356     * Outputs this period as a {@code String}.
357     * <p>
358     * The output will include the period amounts and chronology.
359     *
360     * @return a string representation of this period, not null
361     */
362    @Override
363    String toString();
364
365}
366