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