001/*
002 *  Copyright 2001-2013 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time;
017
018import org.joda.convert.FromString;
019import org.joda.convert.ToString;
020import org.joda.time.base.BaseSingleFieldPeriod;
021import org.joda.time.field.FieldUtils;
022import org.joda.time.format.ISOPeriodFormat;
023import org.joda.time.format.PeriodFormatter;
024
025/**
026 * An immutable time period representing a number of years.
027 * <p>
028 * <code>Years</code> is an immutable period that can only store years.
029 * It does not store months, days or hours for example. As such it is a
030 * type-safe way of representing a number of years in an application.
031 * <p>
032 * The number of years is set in the constructor, and may be queried using
033 * <code>getYears()</code>. Basic mathematical operations are provided -
034 * <code>plus()</code>, <code>minus()</code>, <code>multipliedBy()</code> and
035 * <code>dividedBy()</code>.
036 * <p>
037 * <code>Years</code> is thread-safe and immutable.
038 *
039 * @author Stephen Colebourne
040 * @since 1.4
041 */
042public final class Years extends BaseSingleFieldPeriod {
043
044    /** Constant representing zero years. */
045    public static final Years ZERO = new Years(0);
046    /** Constant representing one year. */
047    public static final Years ONE = new Years(1);
048    /** Constant representing two years. */
049    public static final Years TWO = new Years(2);
050    /** Constant representing three years. */
051    public static final Years THREE = new Years(3);
052    /** Constant representing the maximum number of years that can be stored in this object. */
053    public static final Years MAX_VALUE = new Years(Integer.MAX_VALUE);
054    /** Constant representing the minimum number of years that can be stored in this object. */
055    public static final Years MIN_VALUE = new Years(Integer.MIN_VALUE);
056
057    /** The paser to use for this class. */
058    private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.years());
059    /** Serialization version. */
060    private static final long serialVersionUID = 87525275727380868L;
061
062    //-----------------------------------------------------------------------
063    /**
064     * Obtains an instance of <code>Years</code> that may be cached.
065     * <code>Years</code> is immutable, so instances can be cached and shared.
066     * This factory method provides access to shared instances.
067     *
068     * @param years  the number of years to obtain an instance for
069     * @return the instance of Years
070     */
071    public static Years years(int years) {
072        switch (years) {
073            case 0:
074                return ZERO;
075            case 1:
076                return ONE;
077            case 2:
078                return TWO;
079            case 3:
080                return THREE;
081            case Integer.MAX_VALUE:
082                return MAX_VALUE;
083            case Integer.MIN_VALUE:
084                return MIN_VALUE;
085            default:
086                return new Years(years);
087        }
088    }
089
090    //-----------------------------------------------------------------------
091    /**
092     * Creates a <code>Years</code> representing the number of whole years
093     * between the two specified datetimes. This method corectly handles
094     * any daylight savings time changes that may occur during the interval.
095     *
096     * @param start  the start instant, must not be null
097     * @param end  the end instant, must not be null
098     * @return the period in years
099     * @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}