001    /*
002     *  Copyright 2001-2006 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     */
016    package org.joda.time;
017    
018    import org.joda.time.base.BaseSingleFieldPeriod;
019    import org.joda.time.field.FieldUtils;
020    import org.joda.time.format.ISOPeriodFormat;
021    import org.joda.time.format.PeriodFormatter;
022    
023    /**
024     * An immutable time period representing a number of years.
025     * <p>
026     * <code>Years</code> is an immutable period that can only store years.
027     * It does not store years, days or hours for example. As such it is a
028     * type-safe way of representing a number of years in an application.
029     * <p>
030     * The number of years is set in the constructor, and may be queried using
031     * <code>getYears()</code>. Basic mathematical operations are provided -
032     * <code>plus()</code>, <code>minus()</code>, <code>multipliedBy()</code> and
033     * <code>dividedBy()</code>.
034     * <p>
035     * <code>Years</code> is thread-safe and immutable.
036     *
037     * @author Stephen Colebourne
038     * @since 1.4
039     */
040    public final class Years extends BaseSingleFieldPeriod {
041    
042        /** Constant representing zero years. */
043        public static final Years ZERO = new Years(0);
044        /** Constant representing one year. */
045        public static final Years ONE = new Years(1);
046        /** Constant representing two years. */
047        public static final Years TWO = new Years(2);
048        /** Constant representing three years. */
049        public static final Years THREE = new Years(3);
050        /** Constant representing the maximum number of years that can be stored in this object. */
051        public static final Years MAX_VALUE = new Years(Integer.MAX_VALUE);
052        /** Constant representing the minimum number of years that can be stored in this object. */
053        public static final Years MIN_VALUE = new Years(Integer.MIN_VALUE);
054    
055        /** The paser to use for this class. */
056        private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.years());
057        /** Serialization version. */
058        private static final long serialVersionUID = 87525275727380868L;
059    
060        //-----------------------------------------------------------------------
061        /**
062         * Obtains an instance of <code>Years</code> that may be cached.
063         * <code>Years</code> is immutable, so instances can be cached and shared.
064         * This factory method provides access to shared instances.
065         *
066         * @param years  the number of years to obtain an instance for
067         * @return the instance of Years
068         */
069        public static Years years(int years) {
070            switch (years) {
071                case 0:
072                    return ZERO;
073                case 1:
074                    return ONE;
075                case 2:
076                    return TWO;
077                case 3:
078                    return THREE;
079                case Integer.MAX_VALUE:
080                    return MAX_VALUE;
081                case Integer.MIN_VALUE:
082                    return MIN_VALUE;
083                default:
084                    return new Years(years);
085            }
086        }
087    
088        //-----------------------------------------------------------------------
089        /**
090         * Creates a <code>Years</code> representing the number of whole years
091         * between the two specified datetimes. This method corectly handles
092         * any daylight savings time changes that may occur during the interval.
093         *
094         * @param start  the start instant, must not be null
095         * @param end  the end instant, must not be null
096         * @return the period in years
097         * @throws IllegalArgumentException if the instants are null or invalid
098         */
099        public static Years yearsBetween(ReadableInstant start, ReadableInstant end) {
100            int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.years());
101            return Years.years(amount);
102        }
103    
104        /**
105         * Creates a <code>Years</code> representing the number of whole years
106         * between the two specified partial datetimes.
107         * <p>
108         * The two partials must contain the same fields, for example you can specify
109         * two <code>LocalDate</code> objects.
110         *
111         * @param start  the start partial date, must not be null
112         * @param end  the end partial date, must not be null
113         * @return the period in years
114         * @throws IllegalArgumentException if the partials are null or invalid
115         */
116        public static Years yearsBetween(ReadablePartial start, ReadablePartial end) {
117            if (start instanceof LocalDate && end instanceof LocalDate)   {
118                Chronology chrono = DateTimeUtils.getChronology(start.getChronology());
119                int years = chrono.years().getDifference(
120                        ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis());
121                return Years.years(years);
122            }
123            int amount = BaseSingleFieldPeriod.between(start, end, ZERO);
124            return Years.years(amount);
125        }
126    
127        /**
128         * Creates a <code>Years</code> representing the number of whole years
129         * in the specified interval. This method corectly handles any daylight
130         * savings time changes that may occur during the interval.
131         *
132         * @param interval  the interval to extract years from, null returns zero
133         * @return the period in years
134         * @throws IllegalArgumentException if the partials are null or invalid
135         */
136        public static Years yearsIn(ReadableInterval interval) {
137            if (interval == null)   {
138                return Years.ZERO;
139            }
140            int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.years());
141            return Years.years(amount);
142        }
143    
144        /**
145         * Creates a new <code>Years</code> by parsing a string in the ISO8601 format 'PnY'.
146         * <p>
147         * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the
148         * years component may be non-zero. If any other component is non-zero, an exception
149         * will be thrown.
150         *
151         * @param periodStr  the period string, null returns zero
152         * @return the period in years
153         * @throws IllegalArgumentException if the string format is invalid
154         */
155        public static Years parseYears(String periodStr) {
156            if (periodStr == null) {
157                return Years.ZERO;
158            }
159            Period p = PARSER.parsePeriod(periodStr);
160            return Years.years(p.getYears());
161        }
162    
163        //-----------------------------------------------------------------------
164        /**
165         * Creates a new instance representing a number of years.
166         * You should consider using the factory method {@link #years(int)}
167         * instead of the constructor.
168         *
169         * @param years  the number of years to represent
170         */
171        private Years(int years) {
172            super(years);
173        }
174    
175        /**
176         * Resolves singletons.
177         * 
178         * @return the singleton instance
179         */
180        private Object readResolve() {
181            return Years.years(getValue());
182        }
183    
184        //-----------------------------------------------------------------------
185        /**
186         * Gets the duration field type, which is <code>years</code>.
187         *
188         * @return the period type
189         */
190        public DurationFieldType getFieldType() {
191            return DurationFieldType.years();
192        }
193    
194        /**
195         * Gets the period type, which is <code>years</code>.
196         *
197         * @return the period type
198         */
199        public PeriodType getPeriodType() {
200            return PeriodType.years();
201        }
202    
203        //-----------------------------------------------------------------------
204        /**
205         * Gets the number of years that this period represents.
206         *
207         * @return the number of years in the period
208         */
209        public int getYears() {
210            return getValue();
211        }
212    
213        //-----------------------------------------------------------------------
214        /**
215         * Returns a new instance with the specified number of years added.
216         * <p>
217         * This instance is immutable and unaffected by this method call.
218         *
219         * @param years  the amount of years to add, may be negative
220         * @return the new period plus the specified number of years
221         * @throws ArithmeticException if the result overflows an int
222         */
223        public Years plus(int years) {
224            if (years == 0) {
225                return this;
226            }
227            return Years.years(FieldUtils.safeAdd(getValue(), years));
228        }
229    
230        /**
231         * Returns a new instance with the specified number of years added.
232         * <p>
233         * This instance is immutable and unaffected by this method call.
234         *
235         * @param years  the amount of years to add, may be negative, null means zero
236         * @return the new period plus the specified number of years
237         * @throws ArithmeticException if the result overflows an int
238         */
239        public Years plus(Years years) {
240            if (years == null) {
241                return this;
242            }
243            return plus(years.getValue());
244        }
245    
246        //-----------------------------------------------------------------------
247        /**
248         * Returns a new instance with the specified number of years taken away.
249         * <p>
250         * This instance is immutable and unaffected by this method call.
251         *
252         * @param years  the amount of years to take away, may be negative
253         * @return the new period minus the specified number of years
254         * @throws ArithmeticException if the result overflows an int
255         */
256        public Years minus(int years) {
257            return plus(FieldUtils.safeNegate(years));
258        }
259    
260        /**
261         * Returns a new instance with the specified number of years taken away.
262         * <p>
263         * This instance is immutable and unaffected by this method call.
264         *
265         * @param years  the amount of years to take away, may be negative, null means zero
266         * @return the new period minus the specified number of years
267         * @throws ArithmeticException if the result overflows an int
268         */
269        public Years minus(Years years) {
270            if (years == null) {
271                return this;
272            }
273            return minus(years.getValue());
274        }
275    
276        //-----------------------------------------------------------------------
277        /**
278         * Returns a new instance with the years multiplied by the specified scalar.
279         * <p>
280         * This instance is immutable and unaffected by this method call.
281         *
282         * @param scalar  the amount to multiply by, may be negative
283         * @return the new period multiplied by the specified scalar
284         * @throws ArithmeticException if the result overflows an int
285         */
286        public Years multipliedBy(int scalar) {
287            return Years.years(FieldUtils.safeMultiply(getValue(), scalar));
288        }
289    
290        /**
291         * Returns a new instance with the years divided by the specified divisor.
292         * The calculation uses integer division, thus 3 divided by 2 is 1.
293         * <p>
294         * This instance is immutable and unaffected by this method call.
295         *
296         * @param divisor  the amount to divide by, may be negative
297         * @return the new period divided by the specified divisor
298         * @throws ArithmeticException if the divisor is zero
299         */
300        public Years dividedBy(int divisor) {
301            if (divisor == 1) {
302                return this;
303            }
304            return Years.years(getValue() / divisor);
305        }
306    
307        //-----------------------------------------------------------------------
308        /**
309         * Returns a new instance with the years value negated.
310         *
311         * @return the new period with a negated value
312         * @throws ArithmeticException if the result overflows an int
313         */
314        public Years negated() {
315            return Years.years(FieldUtils.safeNegate(getValue()));
316        }
317    
318        //-----------------------------------------------------------------------
319        /**
320         * Is this years instance greater than the specified number of years.
321         *
322         * @param other  the other period, null means zero
323         * @return true if this years instance is greater than the specified one
324         */
325        public boolean isGreaterThan(Years other) {
326            if (other == null) {
327                return getValue() > 0;
328            }
329            return getValue() > other.getValue();
330        }
331    
332        /**
333         * Is this years instance less than the specified number of years.
334         *
335         * @param other  the other period, null means zero
336         * @return true if this years instance is less than the specified one
337         */
338        public boolean isLessThan(Years other) {
339            if (other == null) {
340                return getValue() < 0;
341            }
342            return getValue() < other.getValue();
343        }
344    
345        //-----------------------------------------------------------------------
346        /**
347         * Gets this instance as a String in the ISO8601 duration format.
348         * <p>
349         * For example, "P4Y" represents 4 years.
350         *
351         * @return the value as an ISO8601 string
352         */
353        public String toString() {
354            return "P" + String.valueOf(getValue()) + "Y";
355        }
356    
357    }