View Javadoc

1   /*
2    *  Copyright 2001-2013 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time;
17  
18  import org.joda.convert.FromString;
19  import org.joda.convert.ToString;
20  import org.joda.time.base.BaseSingleFieldPeriod;
21  import org.joda.time.field.FieldUtils;
22  import org.joda.time.format.ISOPeriodFormat;
23  import org.joda.time.format.PeriodFormatter;
24  
25  /**
26   * An immutable time period representing a number of years.
27   * <p>
28   * <code>Years</code> is an immutable period that can only store years.
29   * It does not store months, days or hours for example. As such it is a
30   * type-safe way of representing a number of years in an application.
31   * <p>
32   * The number of years is set in the constructor, and may be queried using
33   * <code>getYears()</code>. Basic mathematical operations are provided -
34   * <code>plus()</code>, <code>minus()</code>, <code>multipliedBy()</code> and
35   * <code>dividedBy()</code>.
36   * <p>
37   * <code>Years</code> is thread-safe and immutable.
38   *
39   * @author Stephen Colebourne
40   * @since 1.4
41   */
42  public final class Years extends BaseSingleFieldPeriod {
43  
44      /** Constant representing zero years. */
45      public static final Years ZERO = new Years(0);
46      /** Constant representing one year. */
47      public static final Years ONE = new Years(1);
48      /** Constant representing two years. */
49      public static final Years TWO = new Years(2);
50      /** Constant representing three years. */
51      public static final Years THREE = new Years(3);
52      /** Constant representing the maximum number of years that can be stored in this object. */
53      public static final Years MAX_VALUE = new Years(Integer.MAX_VALUE);
54      /** Constant representing the minimum number of years that can be stored in this object. */
55      public static final Years MIN_VALUE = new Years(Integer.MIN_VALUE);
56  
57      /** The paser to use for this class. */
58      private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.years());
59      /** Serialization version. */
60      private static final long serialVersionUID = 87525275727380868L;
61  
62      //-----------------------------------------------------------------------
63      /**
64       * Obtains an instance of <code>Years</code> that may be cached.
65       * <code>Years</code> is immutable, so instances can be cached and shared.
66       * This factory method provides access to shared instances.
67       *
68       * @param years  the number of years to obtain an instance for
69       * @return the instance of Years
70       */
71      public static Years years(int years) {
72          switch (years) {
73              case 0:
74                  return ZERO;
75              case 1:
76                  return ONE;
77              case 2:
78                  return TWO;
79              case 3:
80                  return THREE;
81              case Integer.MAX_VALUE:
82                  return MAX_VALUE;
83              case Integer.MIN_VALUE:
84                  return MIN_VALUE;
85              default:
86                  return new Years(years);
87          }
88      }
89  
90      //-----------------------------------------------------------------------
91      /**
92       * Creates a <code>Years</code> representing the number of whole years
93       * between the two specified datetimes. This method corectly handles
94       * any daylight savings time changes that may occur during the interval.
95       *
96       * @param start  the start instant, must not be null
97       * @param end  the end instant, must not be null
98       * @return the period in years
99       * @throws IllegalArgumentException if the instants are null or invalid
100      */
101     public static Years yearsBetween(ReadableInstant start, ReadableInstant end) {
102         int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.years());
103         return Years.years(amount);
104     }
105 
106     /**
107      * Creates a <code>Years</code> representing the number of whole years
108      * between the two specified partial datetimes.
109      * <p>
110      * The two partials must contain the same fields, for example you can specify
111      * two <code>LocalDate</code> objects.
112      *
113      * @param start  the start partial date, must not be null
114      * @param end  the end partial date, must not be null
115      * @return the period in years
116      * @throws IllegalArgumentException if the partials are null or invalid
117      */
118     public static Years yearsBetween(ReadablePartial start, ReadablePartial end) {
119         if (start instanceof LocalDate && end instanceof LocalDate)   {
120             Chronology chrono = DateTimeUtils.getChronology(start.getChronology());
121             int years = chrono.years().getDifference(
122                     ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis());
123             return Years.years(years);
124         }
125         int amount = BaseSingleFieldPeriod.between(start, end, ZERO);
126         return Years.years(amount);
127     }
128 
129     /**
130      * Creates a <code>Years</code> representing the number of whole years
131      * in the specified interval. This method corectly handles any daylight
132      * savings time changes that may occur during the interval.
133      *
134      * @param interval  the interval to extract years from, null returns zero
135      * @return the period in years
136      * @throws IllegalArgumentException if the partials are null or invalid
137      */
138     public static Years yearsIn(ReadableInterval interval) {
139         if (interval == null)   {
140             return Years.ZERO;
141         }
142         int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.years());
143         return Years.years(amount);
144     }
145 
146     /**
147      * Creates a new <code>Years</code> by parsing a string in the ISO8601 format 'PnY'.
148      * <p>
149      * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the
150      * years component may be non-zero. If any other component is non-zero, an exception
151      * will be thrown.
152      *
153      * @param periodStr  the period string, null returns zero
154      * @return the period in years
155      * @throws IllegalArgumentException if the string format is invalid
156      */
157     @FromString
158     public static Years parseYears(String periodStr) {
159         if (periodStr == null) {
160             return Years.ZERO;
161         }
162         Period p = PARSER.parsePeriod(periodStr);
163         return Years.years(p.getYears());
164     }
165 
166     //-----------------------------------------------------------------------
167     /**
168      * Creates a new instance representing a number of years.
169      * You should consider using the factory method {@link #years(int)}
170      * instead of the constructor.
171      *
172      * @param years  the number of years to represent
173      */
174     private Years(int years) {
175         super(years);
176     }
177 
178     /**
179      * Resolves singletons.
180      * 
181      * @return the singleton instance
182      */
183     private Object readResolve() {
184         return Years.years(getValue());
185     }
186 
187     //-----------------------------------------------------------------------
188     /**
189      * Gets the duration field type, which is <code>years</code>.
190      *
191      * @return the period type
192      */
193     public DurationFieldType getFieldType() {
194         return DurationFieldType.years();
195     }
196 
197     /**
198      * Gets the period type, which is <code>years</code>.
199      *
200      * @return the period type
201      */
202     public PeriodType getPeriodType() {
203         return PeriodType.years();
204     }
205 
206     //-----------------------------------------------------------------------
207     /**
208      * Gets the number of years that this period represents.
209      *
210      * @return the number of years in the period
211      */
212     public int getYears() {
213         return getValue();
214     }
215 
216     //-----------------------------------------------------------------------
217     /**
218      * Returns a new instance with the specified number of years added.
219      * <p>
220      * This instance is immutable and unaffected by this method call.
221      *
222      * @param years  the amount of years to add, may be negative
223      * @return the new period plus the specified number of years
224      * @throws ArithmeticException if the result overflows an int
225      */
226     public Years plus(int years) {
227         if (years == 0) {
228             return this;
229         }
230         return Years.years(FieldUtils.safeAdd(getValue(), years));
231     }
232 
233     /**
234      * Returns a new instance with the specified number of years added.
235      * <p>
236      * This instance is immutable and unaffected by this method call.
237      *
238      * @param years  the amount of years to add, may be negative, null means zero
239      * @return the new period plus the specified number of years
240      * @throws ArithmeticException if the result overflows an int
241      */
242     public Years plus(Years years) {
243         if (years == null) {
244             return this;
245         }
246         return plus(years.getValue());
247     }
248 
249     //-----------------------------------------------------------------------
250     /**
251      * Returns a new instance with the specified number of years taken away.
252      * <p>
253      * This instance is immutable and unaffected by this method call.
254      *
255      * @param years  the amount of years to take away, may be negative
256      * @return the new period minus the specified number of years
257      * @throws ArithmeticException if the result overflows an int
258      */
259     public Years minus(int years) {
260         return plus(FieldUtils.safeNegate(years));
261     }
262 
263     /**
264      * Returns a new instance with the specified number of years taken away.
265      * <p>
266      * This instance is immutable and unaffected by this method call.
267      *
268      * @param years  the amount of years to take away, may be negative, null means zero
269      * @return the new period minus the specified number of years
270      * @throws ArithmeticException if the result overflows an int
271      */
272     public Years minus(Years years) {
273         if (years == null) {
274             return this;
275         }
276         return minus(years.getValue());
277     }
278 
279     //-----------------------------------------------------------------------
280     /**
281      * Returns a new instance with the years multiplied by the specified scalar.
282      * <p>
283      * This instance is immutable and unaffected by this method call.
284      *
285      * @param scalar  the amount to multiply by, may be negative
286      * @return the new period multiplied by the specified scalar
287      * @throws ArithmeticException if the result overflows an int
288      */
289     public Years multipliedBy(int scalar) {
290         return Years.years(FieldUtils.safeMultiply(getValue(), scalar));
291     }
292 
293     /**
294      * Returns a new instance with the years divided by the specified divisor.
295      * The calculation uses integer division, thus 3 divided by 2 is 1.
296      * <p>
297      * This instance is immutable and unaffected by this method call.
298      *
299      * @param divisor  the amount to divide by, may be negative
300      * @return the new period divided by the specified divisor
301      * @throws ArithmeticException if the divisor is zero
302      */
303     public Years dividedBy(int divisor) {
304         if (divisor == 1) {
305             return this;
306         }
307         return Years.years(getValue() / divisor);
308     }
309 
310     //-----------------------------------------------------------------------
311     /**
312      * Returns a new instance with the years value negated.
313      *
314      * @return the new period with a negated value
315      * @throws ArithmeticException if the result overflows an int
316      */
317     public Years negated() {
318         return Years.years(FieldUtils.safeNegate(getValue()));
319     }
320 
321     //-----------------------------------------------------------------------
322     /**
323      * Is this years instance greater than the specified number of years.
324      *
325      * @param other  the other period, null means zero
326      * @return true if this years instance is greater than the specified one
327      */
328     public boolean isGreaterThan(Years other) {
329         if (other == null) {
330             return getValue() > 0;
331         }
332         return getValue() > other.getValue();
333     }
334 
335     /**
336      * Is this years instance less than the specified number of years.
337      *
338      * @param other  the other period, null means zero
339      * @return true if this years instance is less than the specified one
340      */
341     public boolean isLessThan(Years other) {
342         if (other == null) {
343             return getValue() < 0;
344         }
345         return getValue() < other.getValue();
346     }
347 
348     //-----------------------------------------------------------------------
349     /**
350      * Gets this instance as a String in the ISO8601 duration format.
351      * <p>
352      * For example, "P4Y" represents 4 years.
353      *
354      * @return the value as an ISO8601 string
355      */
356     @ToString
357     public String toString() {
358         return "P" + String.valueOf(getValue()) + "Y";
359     }
360 
361 }