001    /*
002     *  Copyright 2001-2009 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    /**
019     * Defines the calculation engine for duration fields.
020     * The interface defines a set of methods that manipulate a millisecond duration
021     * with regards to a single field, such as months or seconds.
022     * <p>
023     * This design is extensible so, if you wish, you can extract a different field from
024     * the millisecond duration. A number of standard implementations are provided to assist.
025     *
026     * @author Stephen Colebourne
027     * @author Brian S O'Neill
028     * @since 1.0
029     */
030    public abstract class DurationField implements Comparable<DurationField> {
031    
032        /**
033         * Get the type of the field.
034         * 
035         * @return field type
036         */
037        public abstract DurationFieldType getType();
038    
039        /**
040         * Get the name of the field.
041         * <p>
042         * By convention, names are plural.
043         * 
044         * @return field name
045         */
046        public abstract String getName();
047    
048        /**
049         * Returns true if this field is supported.
050         * 
051         * @return true if this field is supported
052         */
053        public abstract boolean isSupported();
054    
055        /**
056         * Is this field precise. A precise field can calculate its value from
057         * milliseconds without needing a reference date. Put another way, a
058         * precise field's unit size is not variable.
059         * 
060         * @return true if precise
061         * @see #getUnitMillis()
062         */
063        public abstract boolean isPrecise();
064        
065        /**
066         * Returns the amount of milliseconds per unit value of this field. For
067         * example, if this field represents "seconds", then this returns the
068         * milliseconds in one second.
069         * <p>
070         * For imprecise fields, the unit size is variable, and so this method
071         * returns a suitable average value.
072         *
073         * @return the unit size of this field, in milliseconds
074         * @see #isPrecise()
075         */
076        public abstract long getUnitMillis();
077    
078        //------------------------------------------------------------------------
079        /**
080         * Get the value of this field from the milliseconds, which is approximate
081         * if this field is imprecise.
082         *
083         * @param duration  the milliseconds to query, which may be negative
084         * @return the value of the field, in the units of the field, which may be
085         * negative
086         * @throws ArithmeticException if the value is too large for an int
087         */
088        public abstract int getValue(long duration);
089    
090        /**
091         * Get the value of this field from the milliseconds, which is approximate
092         * if this field is imprecise.
093         *
094         * @param duration  the milliseconds to query, which may be negative
095         * @return the value of the field, in the units of the field, which may be
096         * negative
097         */
098        public abstract long getValueAsLong(long duration);
099    
100        /**
101         * Get the value of this field from the milliseconds relative to an
102         * instant. For precise fields this method produces the same result as for
103         * the single argument get method.
104         * <p>
105         * If the millisecond duration is positive, then the instant is treated as a
106         * "start instant". If negative, the instant is treated as an "end instant".
107         * 
108         * @param duration  the milliseconds to query, which may be negative
109         * @param instant  the start instant to calculate relative to
110         * @return the value of the field, in the units of the field, which may be
111         * negative
112         * @throws ArithmeticException if the value is too large for an int
113         */
114        public abstract int getValue(long duration, long instant);
115    
116        /**
117         * Get the value of this field from the milliseconds relative to an
118         * instant. For precise fields this method produces the same result as for
119         * the single argument get method.
120         * <p>
121         * If the millisecond duration is positive, then the instant is treated as a
122         * "start instant". If negative, the instant is treated as an "end instant".
123         * 
124         * @param duration  the milliseconds to query, which may be negative
125         * @param instant  the start instant to calculate relative to
126         * @return the value of the field, in the units of the field, which may be
127         * negative
128         */
129        public abstract long getValueAsLong(long duration, long instant);
130    
131        //------------------------------------------------------------------------
132        /**
133         * Get the millisecond duration of this field from its value, which is
134         * approximate if this field is imprecise.
135         * 
136         * @param value  the value of the field, which may be negative
137         * @return the milliseconds that the field represents, which may be
138         * negative
139         */
140        public abstract long getMillis(int value);
141    
142        /**
143         * Get the millisecond duration of this field from its value, which is
144         * approximate if this field is imprecise.
145         * 
146         * @param value  the value of the field, which may be negative
147         * @return the milliseconds that the field represents, which may be
148         * negative
149         */
150        public abstract long getMillis(long value);
151    
152        /**
153         * Get the millisecond duration of this field from its value relative to an
154         * instant. For precise fields this method produces the same result as for
155         * the single argument getMillis method.
156         * <p>
157         * If the value is positive, then the instant is treated as a "start
158         * instant". If negative, the instant is treated as an "end instant".
159         *
160         * @param value  the value of the field, which may be negative
161         * @param instant  the instant to calculate relative to
162         * @return the millisecond duration that the field represents, which may be
163         * negative
164         */
165        public abstract long getMillis(int value, long instant);
166    
167        /**
168         * Get the millisecond duration of this field from its value relative to an
169         * instant. For precise fields this method produces the same result as for
170         * the single argument getMillis method.
171         * <p>
172         * If the value is positive, then the instant is treated as a "start
173         * instant". If negative, the instant is treated as an "end instant".
174         *
175         * @param value  the value of the field, which may be negative
176         * @param instant  the instant to calculate relative to
177         * @return the millisecond duration that the field represents, which may be
178         * negative
179         */
180        public abstract long getMillis(long value, long instant);
181    
182        /**
183         * Adds a duration value (which may be negative) to the instant.
184         * 
185         * @param instant  the milliseconds from 1970-01-01T00:00:00Z to add to
186         * @param value  the value to add, in the units of the field
187         * @return the updated milliseconds
188         */
189        public abstract long add(long instant, int value);
190    
191        /**
192         * Adds a duration value (which may be negative) to the instant.
193         * 
194         * @param instant  the milliseconds from 1970-01-01T00:00:00Z to add to
195         * @param value  the value to add, in the units of the field
196         * @return the updated milliseconds
197         */
198        public abstract long add(long instant, long value);
199    
200        /**
201         * Subtracts a duration value (which may be negative) from the instant.
202         * 
203         * @param instant  the milliseconds from 1970-01-01T00:00:00Z to subtract from
204         * @param value  the value to subtract, in the units of the field
205         * @return the updated milliseconds
206         * @since 1.1
207         */
208        public long subtract(long instant, int value) {
209            if (value == Integer.MIN_VALUE) {
210                return subtract(instant, (long) value);
211            }
212            return add(instant, -value);
213        }
214    
215        /**
216         * Subtracts a duration value (which may be negative) from the instant.
217         * 
218         * @param instant  the milliseconds from 1970-01-01T00:00:00Z to subtract from
219         * @param value  the value to subtract, in the units of the field
220         * @return the updated milliseconds
221         * @since 1.1
222         */
223        public long subtract(long instant, long value) {
224            if (value == Long.MIN_VALUE) {
225                throw new ArithmeticException("Long.MIN_VALUE cannot be negated");
226            }
227            return add(instant, -value);
228        }
229    
230        /**
231         * Computes the difference between two instants, as measured in the units
232         * of this field. Any fractional units are dropped from the result. Calling
233         * getDifference reverses the effect of calling add. In the following code:
234         *
235         * <pre>
236         * long instant = ...
237         * int v = ...
238         * int age = getDifference(add(instant, v), instant);
239         * </pre>
240         *
241         * The value 'age' is the same as the value 'v'.
242         *
243         * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
244         * subtract from
245         * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
246         * subtract off the minuend
247         * @return the difference in the units of this field
248         */
249        public abstract int getDifference(long minuendInstant, long subtrahendInstant);
250    
251        /**
252         * Computes the difference between two instants, as measured in the units
253         * of this field. Any fractional units are dropped from the result. Calling
254         * getDifference reverses the effect of calling add. In the following code:
255         *
256         * <pre>
257         * long instant = ...
258         * long v = ...
259         * long age = getDifferenceAsLong(add(instant, v), instant);
260         * </pre>
261         *
262         * The value 'age' is the same as the value 'v'.
263         *
264         * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
265         * subtract from
266         * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
267         * subtract off the minuend
268         * @return the difference in the units of this field
269         */
270        public abstract long getDifferenceAsLong(long minuendInstant, long subtrahendInstant);
271    
272        // Adding this definition would be backwards incompatible with earlier subclasses
273        // This definition of compareTo was present in previous versions, and still applies
274    //    /**
275    //     * Compares this duration field with another duration field for ascending
276    //     * unit millisecond order. This ordering is inconsistent with equals, as it
277    //     * ignores name and precision.
278    //     *
279    //     * @param durationField  a duration field to check against
280    //     * @return negative value if this is less, 0 if equal, or positive value if greater
281    //     * @throws NullPointerException if the object is null
282    //     * @throws ClassCastException if the object type is not supported
283    //     */
284    //    public abstract int compareTo(DurationField durationField);
285    
286        /**
287         * Returns a localized unit name of this field, using the given value as an
288         * aid. For example, the unit name may differ if it is plural.
289         *
290         * @param value the duration value to use for selecting a unit name
291         * @param locale the locale to use for selecting a name, null for default
292         */
293        //String getUnitName(long value, Locale locale);
294    
295        /**
296         * Returns a localized unit name of this field, using the given value as an
297         * aid. For example, the unit name may differ if it is plural.
298         *
299         * @param value the duration value to use for selecting a unit name
300         */
301        //String getUnitName(long value);
302    
303        /**
304         * Get the maximum length string returned by getUnitName.
305         * 
306         * @param locale the locale to use for selecting a unit name, null for
307         * default
308         * @return the maximum name length
309         */
310        //int getMaximumUnitNameLength(Locale locale);
311    
312        //------------------------------------------------------------------------
313        /**
314         * Get a suitable debug string.
315         * 
316         * @return debug string
317         */
318        public abstract String toString();
319        
320    }