KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > base > BaseSingleFieldPeriod


1 /*
2  * Copyright 2001-2006 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.base;
17
18 import java.io.Serializable JavaDoc;
19
20 import org.joda.time.Chronology;
21 import org.joda.time.DateTimeUtils;
22 import org.joda.time.DurationField;
23 import org.joda.time.DurationFieldType;
24 import org.joda.time.MutablePeriod;
25 import org.joda.time.Period;
26 import org.joda.time.PeriodType;
27 import org.joda.time.ReadableInstant;
28 import org.joda.time.ReadablePartial;
29 import org.joda.time.ReadablePeriod;
30 import org.joda.time.chrono.ISOChronology;
31 import org.joda.time.field.FieldUtils;
32
33 /**
34  * BaseSingleFieldPeriod is an abstract implementation of ReadablePeriod that
35  * manages a single duration field, such as days or minutes.
36  * <p>
37  * This class should generally not be used directly by API users.
38  * The {@link ReadablePeriod} interface should be used when different
39  * kinds of period objects are to be referenced.
40  * <p>
41  * BaseSingleFieldPeriod subclasses may be mutable and not thread-safe.
42  *
43  * @author Stephen Colebourne
44  * @since 1.4
45  */

46 public abstract class BaseSingleFieldPeriod
47         implements ReadablePeriod, Comparable JavaDoc, Serializable JavaDoc {
48
49     /** Serialization version. */
50     private static final long serialVersionUID = 9386874258972L;
51
52     /** The period in the units of this period. */
53     private int iPeriod;
54
55     //-----------------------------------------------------------------------
56
/**
57      * Calculates the number of whole units between the two specified datetimes.
58      *
59      * @param start the start instant, validated to not be null
60      * @param end the end instant, validated to not be null
61      * @param field the field type to use, must not be null
62      * @return the period
63      * @throws IllegalArgumentException if the instants are null or invalid
64      */

65     protected static int between(ReadableInstant start, ReadableInstant end, DurationFieldType field) {
66         if (start == null || end == null) {
67             throw new IllegalArgumentException JavaDoc("ReadableInstant objects must not be null");
68         }
69         Chronology chrono = DateTimeUtils.getInstantChronology(start);
70         int amount = field.getField(chrono).getDifference(end.getMillis(), start.getMillis());
71         return amount;
72     }
73
74     //-----------------------------------------------------------------------
75
/**
76      * Calculates the number of whole units between the two specified partial datetimes.
77      * <p>
78      * The two partials must contain the same fields, for example you can specify
79      * two <code>LocalDate</code> objects.
80      *
81      * @param start the start partial date, validated to not be null
82      * @param end the end partial date, validated to not be null
83      * @param zeroInstance the zero instance constant, must not be null
84      * @return the period
85      * @throws IllegalArgumentException if the partials are null or invalid
86      */

87     protected static int between(ReadablePartial start, ReadablePartial end, ReadablePeriod zeroInstance) {
88         if (start == null || end == null) {
89             throw new IllegalArgumentException JavaDoc("ReadablePartial objects must not be null");
90         }
91         if (start.size() != end.size()) {
92             throw new IllegalArgumentException JavaDoc("ReadablePartial objects must have the same set of fields");
93         }
94         for (int i = 0, isize = start.size(); i < isize; i++) {
95             if (start.getFieldType(i) != end.getFieldType(i)) {
96                 throw new IllegalArgumentException JavaDoc("ReadablePartial objects must have the same set of fields");
97             }
98         }
99         if (DateTimeUtils.isContiguous(start) == false) {
100             throw new IllegalArgumentException JavaDoc("ReadablePartial objects must be contiguous");
101         }
102         Chronology chrono = DateTimeUtils.getChronology(start.getChronology()).withUTC();
103         int[] values = chrono.get(zeroInstance, chrono.set(start, 0L), chrono.set(end, 0L));
104         return values[0];
105     }
106
107     /**
108      * Creates a new instance representing the number of complete standard length units
109      * in the specified period.
110      * <p>
111      * This factory method converts all fields from the period to hours using standardised
112      * durations for each field. Only those fields which have a precise duration in
113      * the ISO UTC chronology can be converted.
114      * <ul>
115      * <li>One week consists of 7 days.
116      * <li>One day consists of 24 hours.
117      * <li>One hour consists of 60 minutes.
118      * <li>One minute consists of 60 seconds.
119      * <li>One second consists of 1000 milliseconds.
120      * </ul>
121      * Months and Years are imprecise and periods containing these values cannot be converted.
122      *
123      * @param period the period to get the number of hours from, must not be null
124      * @param millisPerUnit the number of milliseconds in one standard unit of this period
125      * @throws IllegalArgumentException if the period contains imprecise duration values
126      */

127     protected static int standardPeriodIn(ReadablePeriod period, long millisPerUnit) {
128         if (period == null) {
129             return 0;
130         }
131         Chronology iso = ISOChronology.getInstanceUTC();
132         long duration = 0L;
133         for (int i = 0; i < period.size(); i++) {
134             int value = period.getValue(i);
135             if (value != 0) {
136                 DurationField field = period.getFieldType(i).getField(iso);
137                 if (field.isPrecise() == false) {
138                     throw new IllegalArgumentException JavaDoc(
139                             "Cannot convert period to duration as " + field.getName() +
140                             " is not precise in the period " + period);
141                 }
142                 duration = FieldUtils.safeAdd(duration, FieldUtils.safeMultiply(field.getUnitMillis(), value));
143             }
144         }
145         return FieldUtils.safeToInt(duration / millisPerUnit);
146     }
147
148     //-----------------------------------------------------------------------
149
/**
150      * Creates a new instance representing the specified period.
151      *
152      * @param period the period to represent
153      */

154     protected BaseSingleFieldPeriod(int period) {
155         super();
156         iPeriod = period;
157     }
158
159     //-----------------------------------------------------------------------
160
/**
161      * Gets the amount of this period.
162      *
163      * @return the period value
164      */

165     protected int getValue() {
166         return iPeriod;
167     }
168
169     /**
170      * Sets the amount of this period.
171      * To make a subclass immutable you must declare it final, or block this method.
172      *
173      * @param value the period value
174      */

175     protected void setValue(int value) {
176         iPeriod = value;
177     }
178
179     //-----------------------------------------------------------------------
180
/**
181      * Gets the single duration field type.
182      *
183      * @return the duration field type, not null
184      */

185     public abstract DurationFieldType getFieldType();
186
187     /**
188      * Gets the period type which matches the duration field type.
189      *
190      * @return the period type, not null
191      */

192     public abstract PeriodType getPeriodType();
193
194     //-----------------------------------------------------------------------
195
/**
196      * Gets the number of fields that this period supports, which is one.
197      *
198      * @return the number of fields supported, which is one
199      */

200     public int size() {
201         return 1;
202     }
203
204     /**
205      * Gets the field type at the specified index.
206      * <p>
207      * The only index supported by this period is zero which returns the
208      * field type of this class.
209      *
210      * @param index the index to retrieve, which must be zero
211      * @return the field at the specified index
212      * @throws IndexOutOfBoundsException if the index is invalid
213      */

214     public DurationFieldType getFieldType(int index) {
215         if (index != 0) {
216             throw new IndexOutOfBoundsException JavaDoc(String.valueOf(index));
217         }
218         return getFieldType();
219     }
220
221     /**
222      * Gets the value at the specified index.
223      * <p>
224      * The only index supported by this period is zero.
225      *
226      * @param index the index to retrieve, which must be zero
227      * @return the value of the field at the specified index
228      * @throws IndexOutOfBoundsException if the index is invalid
229      */

230     public int getValue(int index) {
231         if (index != 0) {
232             throw new IndexOutOfBoundsException JavaDoc(String.valueOf(index));
233         }
234         return getValue();
235     }
236
237     /**
238      * Gets the value of a duration field represented by this period.
239      * <p>
240      * If the field type specified does not match the type used by this class
241      * then zero is returned.
242      *
243      * @param type the field type to query, null returns zero
244      * @return the value of that field, zero if field not supported
245      */

246     public int get(DurationFieldType type) {
247         if (type == getFieldType()) {
248             return getValue();
249         }
250         return 0;
251     }
252
253     /**
254      * Checks whether the duration field specified is supported by this period.
255      *
256      * @param type the type to check, may be null which returns false
257      * @return true if the field is supported
258      */

259     public boolean isSupported(DurationFieldType type) {
260         return (type == getFieldType());
261     }
262
263     //-----------------------------------------------------------------------
264
/**
265      * Get this period as an immutable <code>Period</code> object.
266      * The period will use <code>PeriodType.standard()</code>.
267      *
268      * @return a <code>Period</code> representing the same number of days
269      */

270     public Period toPeriod() {
271         return Period.ZERO.withFields(this);
272     }
273
274     /**
275      * Get this object as a <code>MutablePeriod</code>.
276      * <p>
277      * This will always return a new <code>MutablePeriod</code> with the same fields.
278      * The period will use <code>PeriodType.standard()</code>.
279      *
280      * @return a MutablePeriod using the same field set and values
281      */

282     public MutablePeriod toMutablePeriod() {
283         MutablePeriod period = new MutablePeriod();
284         period.add(this);
285         return period;
286     }
287
288     //-----------------------------------------------------------------------
289
/**
290      * Compares this object with the specified object for equality based on the
291      * value of each field. All ReadablePeriod instances are accepted, but only
292      * those with a matching <code>PeriodType</code> can return true.
293      *
294      * @param period a readable period to check against
295      * @return true if all the field values are equal, false if
296      * not or the period is null or of an incorrect type
297      */

298     public boolean equals(Object JavaDoc period) {
299         if (this == period) {
300             return true;
301         }
302         if (period instanceof ReadablePeriod == false) {
303             return false;
304         }
305         ReadablePeriod other = (ReadablePeriod) period;
306         return (other.getPeriodType() == getPeriodType() && other.getValue(0) == getValue());
307     }
308
309     /**
310      * Gets a hash code for the period as defined by ReadablePeriod.
311      *
312      * @return a hash code
313      */

314     public int hashCode() {
315         int total = 17;
316         total = 27 * total + getValue();
317         total = 27 * total + getFieldType().hashCode();
318         return total;
319     }
320
321     /**
322      * Compares this period to another object of the same class.
323      *
324      * @param other the other period, must not be null
325      * @return zero if equal, positive if greater, negative if less
326      * @throws NullPointerException if the other period is null
327      * @throws ClassCastException if the other period is of a different type
328      */

329     public int compareTo(Object JavaDoc other) {
330         if (other.getClass() != getClass()) {
331             throw new ClassCastException JavaDoc(getClass() + " cannot be compared to " + other.getClass());
332         }
333         int otherValue = ((BaseSingleFieldPeriod) other).getValue();
334         int thisValue = getValue();
335         if (thisValue > otherValue) {
336             return 1;
337         }
338         if (thisValue < otherValue) {
339             return -1;
340         }
341         return 0;
342     }
343
344 }
345
Popular Tags