KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > field > BaseDateTimeField


1 /*
2  * Copyright 2001-2005 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.field;
17
18 import java.util.Locale JavaDoc;
19
20 import org.joda.time.DateTimeField;
21 import org.joda.time.DateTimeFieldType;
22 import org.joda.time.DurationField;
23 import org.joda.time.IllegalFieldValueException;
24 import org.joda.time.ReadablePartial;
25
26 /**
27  * BaseDateTimeField provides the common behaviour for DateTimeField
28  * implementations.
29  * <p>
30  * This class should generally not be used directly by API users. The
31  * DateTimeField class should be used when different kinds of DateTimeField
32  * objects are to be referenced.
33  * <p>
34  * BaseDateTimeField is thread-safe and immutable, and its subclasses must
35  * be as well.
36  *
37  * @author Brian S O'Neill
38  * @since 1.0
39  * @see DecoratedDateTimeField
40  */

41 public abstract class BaseDateTimeField extends DateTimeField {
42
43     /** The field type. */
44     private final DateTimeFieldType iType;
45
46     /**
47      * Constructor.
48      */

49     protected BaseDateTimeField(DateTimeFieldType type) {
50         super();
51         if (type == null) {
52             throw new IllegalArgumentException JavaDoc("The type must not be null");
53         }
54         iType = type;
55     }
56     
57     public final DateTimeFieldType getType() {
58         return iType;
59     }
60
61     public final String JavaDoc getName() {
62         return iType.getName();
63     }
64
65     /**
66      * @return true always
67      */

68     public final boolean isSupported() {
69         return true;
70     }
71
72     // Main access API
73
//------------------------------------------------------------------------
74
/**
75      * Get the value of this field from the milliseconds.
76      *
77      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
78      * @return the value of the field, in the units of the field
79      */

80     public abstract int get(long instant);
81
82     //-----------------------------------------------------------------------
83
/**
84      * Get the human-readable, text value of this field from the milliseconds.
85      * If the specified locale is null, the default locale is used.
86      * <p>
87      * The default implementation returns getAsText(get(instant), locale).
88      *
89      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
90      * @param locale the locale to use for selecting a text symbol, null means default
91      * @return the text value of the field
92      */

93     public String JavaDoc getAsText(long instant, Locale JavaDoc locale) {
94         return getAsText(get(instant), locale);
95     }
96
97     /**
98      * Get the human-readable, text value of this field from the milliseconds.
99      * <p>
100      * The default implementation calls {@link #getAsText(long, Locale)}.
101      *
102      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
103      * @return the text value of the field
104      */

105     public final String JavaDoc getAsText(long instant) {
106         return getAsText(instant, null);
107     }
108
109     /**
110      * Get the human-readable, text value of this field from a partial instant.
111      * If the specified locale is null, the default locale is used.
112      * <p>
113      * The default implementation returns getAsText(fieldValue, locale).
114      *
115      * @param partial the partial instant to query
116      * @param fieldValue the field value of this field, provided for performance
117      * @param locale the locale to use for selecting a text symbol, null for default
118      * @return the text value of the field
119      */

120     public String JavaDoc getAsText(ReadablePartial partial, int fieldValue, Locale JavaDoc locale) {
121         return getAsText(fieldValue, locale);
122     }
123
124     /**
125      * Get the human-readable, text value of this field from a partial instant.
126      * If the specified locale is null, the default locale is used.
127      * <p>
128      * The default implementation calls {@link ReadablePartial#get(DateTimeFieldType)}
129      * and {@link #getAsText(ReadablePartial, int, Locale)}.
130      *
131      * @param partial the partial instant to query
132      * @param locale the locale to use for selecting a text symbol, null for default
133      * @return the text value of the field
134      */

135     public final String JavaDoc getAsText(ReadablePartial partial, Locale JavaDoc locale) {
136         return getAsText(partial, partial.get(getType()), locale);
137     }
138
139     /**
140      * Get the human-readable, text value of this field from the field value.
141      * If the specified locale is null, the default locale is used.
142      * <p>
143      * The default implementation returns Integer.toString(get(instant)).
144      * <p>
145      * Note: subclasses that override this method should also override
146      * getMaximumTextLength.
147      *
148      * @param fieldValue the numeric value to convert to text
149      * @param locale the locale to use for selecting a text symbol, null for default
150      * @return the text value of the field
151      */

152     public String JavaDoc getAsText(int fieldValue, Locale JavaDoc locale) {
153         return Integer.toString(fieldValue);
154     }
155
156     //-----------------------------------------------------------------------
157
/**
158      * Get the human-readable, short text value of this field from the milliseconds.
159      * If the specified locale is null, the default locale is used.
160      * <p>
161      * The default implementation returns getAsShortText(get(instant), locale).
162      *
163      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
164      * @param locale the locale to use for selecting a text symbol, null means default
165      * @return the text value of the field
166      */

167     public String JavaDoc getAsShortText(long instant, Locale JavaDoc locale) {
168         return getAsShortText(get(instant), locale);
169     }
170
171     /**
172      * Get the human-readable, short text value of this field from the milliseconds.
173      * <p>
174      * The default implementation calls {@link #getAsShortText(long, Locale)}.
175      *
176      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
177      * @return the text value of the field
178      */

179     public final String JavaDoc getAsShortText(long instant) {
180         return getAsShortText(instant, null);
181     }
182
183     /**
184      * Get the human-readable, short text value of this field from a partial instant.
185      * If the specified locale is null, the default locale is used.
186      * <p>
187      * The default implementation returns getAsShortText(fieldValue, locale).
188      *
189      * @param partial the partial instant to query
190      * @param fieldValue the field value of this field, provided for performance
191      * @param locale the locale to use for selecting a text symbol, null for default
192      * @return the text value of the field
193      */

194     public String JavaDoc getAsShortText(ReadablePartial partial, int fieldValue, Locale JavaDoc locale) {
195         return getAsShortText(fieldValue, locale);
196     }
197
198     /**
199      * Get the human-readable, short text value of this field from a partial instant.
200      * If the specified locale is null, the default locale is used.
201      * <p>
202      * The default implementation calls {@link ReadablePartial#get(DateTimeFieldType)}
203      * and {@link #getAsText(ReadablePartial, int, Locale)}.
204      *
205      * @param partial the partial instant to query
206      * @param locale the locale to use for selecting a text symbol, null for default
207      * @return the text value of the field
208      */

209     public final String JavaDoc getAsShortText(ReadablePartial partial, Locale JavaDoc locale) {
210         return getAsShortText(partial, partial.get(getType()), locale);
211     }
212
213     /**
214      * Get the human-readable, short text value of this field from the field value.
215      * If the specified locale is null, the default locale is used.
216      * <p>
217      * The default implementation returns getAsText(fieldValue, locale).
218      * <p>
219      * Note: subclasses that override this method should also override
220      * getMaximumShortTextLength.
221      *
222      * @param fieldValue the numeric value to convert to text
223      * @param locale the locale to use for selecting a text symbol, null for default
224      * @return the text value of the field
225      */

226     public String JavaDoc getAsShortText(int fieldValue, Locale JavaDoc locale) {
227         return getAsText(fieldValue, locale);
228     }
229
230     //-----------------------------------------------------------------------
231
/**
232      * Adds a value (which may be negative) to the instant value,
233      * overflowing into larger fields if necessary.
234      * <p>
235      * The value will be added to this field. If the value is too large to be
236      * added solely to this field, larger fields will increase as required.
237      * Smaller fields should be unaffected, except where the result would be
238      * an invalid value for a smaller field. In this case the smaller field is
239      * adjusted to be in range.
240      * <p>
241      * For example, in the ISO chronology:<br>
242      * 2000-08-20 add six months is 2001-02-20<br>
243      * 2000-08-20 add twenty months is 2002-04-20<br>
244      * 2000-08-20 add minus nine months is 1999-11-20<br>
245      * 2001-01-31 add one month is 2001-02-28<br>
246      * 2001-01-31 add two months is 2001-03-31<br>
247      *
248      * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to
249      * @param value the value to add, in the units of the field
250      * @return the updated milliseconds
251      */

252     public long add(long instant, int value) {
253         return getDurationField().add(instant, value);
254     }
255
256     /**
257      * Adds a value (which may be negative) to the instant value,
258      * overflowing into larger fields if necessary.
259      *
260      * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to
261      * @param value the long value to add, in the units of the field
262      * @return the updated milliseconds
263      * @throws IllegalArgumentException if value is too large
264      * @see #add(long,int)
265      */

266     public long add(long instant, long value) {
267         return getDurationField().add(instant, value);
268     }
269
270     /**
271      * Adds a value (which may be negative) to the partial instant,
272      * throwing an exception if the maximum size of the instant is reached.
273      * <p>
274      * The value will be added to this field, overflowing into larger fields
275      * if necessary. Smaller fields should be unaffected, except where the
276      * result would be an invalid value for a smaller field. In this case the
277      * smaller field is adjusted to be in range.
278      * <p>
279      * Partial instants only contain some fields. This may result in a maximum
280      * possible value, such as TimeOfDay being limited to 23:59:59:999. If this
281      * limit is breached by the add an exception is thrown.
282      * <p>
283      * For example, in the ISO chronology:<br>
284      * 2000-08-20 add six months is 2000-02-20<br>
285      * 2000-08-20 add twenty months is 2000-04-20<br>
286      * 2000-08-20 add minus nine months is 2000-11-20<br>
287      * 2001-01-31 add one month is 2001-02-28<br>
288      * 2001-01-31 add two months is 2001-03-31<br>
289      *
290      * @param instant the partial instant
291      * @param fieldIndex the index of this field in the partial
292      * @param values the values of the partial instant which should be updated
293      * @param valueToAdd the value to add, in the units of the field
294      * @return the passed in values
295      * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached
296      */

297     public int[] add(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) {
298         if (valueToAdd == 0) {
299             return values;
300         }
301         // there are more efficient algorithms than this (especially for time only fields)
302
// trouble is when dealing with days and months, so we use this technique of
303
// adding/removing one from the larger field at a time
304
DateTimeField nextField = null;
305         
306         while (valueToAdd > 0) {
307             int max = getMaximumValue(instant, values);
308             long proposed = values[fieldIndex] + valueToAdd;
309             if (proposed <= max) {
310                 values[fieldIndex] = (int) proposed;
311                 break;
312             }
313             if (nextField == null) {
314                 if (fieldIndex == 0) {
315                     throw new IllegalArgumentException JavaDoc("Maximum value exceeded for add");
316                 }
317                 nextField = instant.getField(fieldIndex - 1);
318                 // test only works if this field is UTC (ie. local)
319
if (getRangeDurationField().getType() != nextField.getDurationField().getType()) {
320                     throw new IllegalArgumentException JavaDoc("Fields invalid for add");
321                 }
322             }
323             valueToAdd -= (max + 1) - values[fieldIndex]; // reduce the amount to add
324
values = nextField.add(instant, fieldIndex - 1, values, 1); // add 1 to next bigger field
325
values[fieldIndex] = getMinimumValue(instant, values); // reset this field to zero
326
}
327         while (valueToAdd < 0) {
328             int min = getMinimumValue(instant, values);
329             long proposed = values[fieldIndex] + valueToAdd;
330             if (proposed >= min) {
331                 values[fieldIndex] = (int) proposed;
332                 break;
333             }
334             if (nextField == null) {
335                 if (fieldIndex == 0) {
336                     throw new IllegalArgumentException JavaDoc("Maximum value exceeded for add");
337                 }
338                 nextField = instant.getField(fieldIndex - 1);
339                 if (getRangeDurationField().getType() != nextField.getDurationField().getType()) {
340                     throw new IllegalArgumentException JavaDoc("Fields invalid for add");
341                 }
342             }
343             valueToAdd -= (min - 1) - values[fieldIndex]; // reduce the amount to add
344
values = nextField.add(instant, fieldIndex - 1, values, -1); // subtract 1 from next bigger field
345
values[fieldIndex] = getMaximumValue(instant, values); // reset this field to max value
346
}
347         
348         return set(instant, fieldIndex, values, values[fieldIndex]); // adjusts smaller fields
349
}
350
351     /**
352      * Adds a value (which may be negative) to the partial instant,
353      * wrapping the whole partial if the maximum size of the partial is reached.
354      * <p>
355      * The value will be added to this field, overflowing into larger fields
356      * if necessary. Smaller fields should be unaffected, except where the
357      * result would be an invalid value for a smaller field. In this case the
358      * smaller field is adjusted to be in range.
359      * <p>
360      * Partial instants only contain some fields. This may result in a maximum
361      * possible value, such as TimeOfDay normally being limited to 23:59:59:999.
362      * If ths limit is reached by the addition, this method will wrap back to
363      * 00:00:00.000. In fact, you would generally only use this method for
364      * classes that have a limitation such as this.
365      * <p>
366      * For example, in the ISO chronology:<br>
367      * 10:20:30 add 20 minutes is 10:40:30<br>
368      * 10:20:30 add 45 minutes is 11:05:30<br>
369      * 10:20:30 add 16 hours is 02:20:30<br>
370      *
371      * @param instant the partial instant
372      * @param fieldIndex the index of this field in the partial
373      * @param values the values of the partial instant which should be updated
374      * @param valueToAdd the value to add, in the units of the field
375      * @return the passed in values
376      * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached
377      */

378     public int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) {
379         if (valueToAdd == 0) {
380             return values;
381         }
382         // there are more efficient algorithms than this (especially for time only fields)
383
// trouble is when dealing with days and months, so we use this technique of
384
// adding/removing one from the larger field at a time
385
DateTimeField nextField = null;
386         
387         while (valueToAdd > 0) {
388             int max = getMaximumValue(instant, values);
389             long proposed = values[fieldIndex] + valueToAdd;
390             if (proposed <= max) {
391                 values[fieldIndex] = (int) proposed;
392                 break;
393             }
394             if (nextField == null) {
395                 if (fieldIndex == 0) {
396                     valueToAdd -= (max + 1) - values[fieldIndex];
397                     values[fieldIndex] = getMinimumValue(instant, values);
398                     continue;
399                 }
400                 nextField = instant.getField(fieldIndex - 1);
401                 // test only works if this field is UTC (ie. local)
402
if (getRangeDurationField().getType() != nextField.getDurationField().getType()) {
403                     throw new IllegalArgumentException JavaDoc("Fields invalid for add");
404                 }
405             }
406             valueToAdd -= (max + 1) - values[fieldIndex]; // reduce the amount to add
407
values = nextField.addWrapPartial(instant, fieldIndex - 1, values, 1); // add 1 to next bigger field
408
values[fieldIndex] = getMinimumValue(instant, values); // reset this field to zero
409
}
410         while (valueToAdd < 0) {
411             int min = getMinimumValue(instant, values);
412             long proposed = values[fieldIndex] + valueToAdd;
413             if (proposed >= min) {
414                 values[fieldIndex] = (int) proposed;
415                 break;
416             }
417             if (nextField == null) {
418                 if (fieldIndex == 0) {
419                     valueToAdd -= (min - 1) - values[fieldIndex];
420                     values[fieldIndex] = getMaximumValue(instant, values);
421                     continue;
422                 }
423                 nextField = instant.getField(fieldIndex - 1);
424                 if (getRangeDurationField().getType() != nextField.getDurationField().getType()) {
425                     throw new IllegalArgumentException JavaDoc("Fields invalid for add");
426                 }
427             }
428             valueToAdd -= (min - 1) - values[fieldIndex]; // reduce the amount to add
429
values = nextField.addWrapPartial(instant, fieldIndex - 1, values, -1); // subtract 1 from next bigger field
430
values[fieldIndex] = getMaximumValue(instant, values); // reset this field to max value
431
}
432         
433         return set(instant, fieldIndex, values, values[fieldIndex]); // adjusts smaller fields
434
}
435
436     /**
437      * Adds a value (which may be negative) to the instant value,
438      * wrapping within this field.
439      * <p>
440      * The value will be added to this field. If the value is too large to be
441      * added solely to this field then it wraps. Larger fields are always
442      * unaffected. Smaller fields should be unaffected, except where the
443      * result would be an invalid value for a smaller field. In this case the
444      * smaller field is adjusted to be in range.
445      * <p>
446      * For example, in the ISO chronology:<br>
447      * 2000-08-20 addWrapField six months is 2000-02-20<br>
448      * 2000-08-20 addWrapField twenty months is 2000-04-20<br>
449      * 2000-08-20 addWrapField minus nine months is 2000-11-20<br>
450      * 2001-01-31 addWrapField one month is 2001-02-28<br>
451      * 2001-01-31 addWrapField two months is 2001-03-31<br>
452      * <p>
453      * The default implementation internally calls set. Subclasses are
454      * encouraged to provide a more efficient implementation.
455      *
456      * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to
457      * @param value the value to add, in the units of the field
458      * @return the updated milliseconds
459      */

460     public long addWrapField(long instant, int value) {
461         int current = get(instant);
462         int wrapped = FieldUtils.getWrappedValue
463             (current, value, getMinimumValue(instant), getMaximumValue(instant));
464         return set(instant, wrapped);
465     }
466
467     /**
468      * Adds a value (which may be negative) to the partial instant,
469      * wrapping within this field.
470      * <p>
471      * The value will be added to this field. If the value is too large to be
472      * added solely to this field then it wraps. Larger fields are always
473      * unaffected. Smaller fields should be unaffected, except where the
474      * result would be an invalid value for a smaller field. In this case the
475      * smaller field is adjusted to be in range.
476      * <p>
477      * For example, in the ISO chronology:<br>
478      * 2000-08-20 addWrapField six months is 2000-02-20<br>
479      * 2000-08-20 addWrapField twenty months is 2000-04-20<br>
480      * 2000-08-20 addWrapField minus nine months is 2000-11-20<br>
481      * 2001-01-31 addWrapField one month is 2001-02-28<br>
482      * 2001-01-31 addWrapField two months is 2001-03-31<br>
483      * <p>
484      * The default implementation internally calls set. Subclasses are
485      * encouraged to provide a more efficient implementation.
486      *
487      * @param instant the partial instant
488      * @param fieldIndex the index of this field in the instant
489      * @param values the values of the partial instant which should be updated
490      * @param valueToAdd the value to add, in the units of the field
491      * @return the passed in values
492      * @throws IllegalArgumentException if the value is invalid
493      */

494     public int[] addWrapField(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) {
495         int current = values[fieldIndex];
496         int wrapped = FieldUtils.getWrappedValue
497             (current, valueToAdd, getMinimumValue(instant), getMaximumValue(instant));
498         return set(instant, fieldIndex, values, wrapped); // adjusts smaller fields
499
}
500
501     //-----------------------------------------------------------------------
502
/**
503      * Computes the difference between two instants, as measured in the units
504      * of this field. Any fractional units are dropped from the result. Calling
505      * getDifference reverses the effect of calling add. In the following code:
506      *
507      * <pre>
508      * long instant = ...
509      * int v = ...
510      * int age = getDifference(add(instant, v), instant);
511      * </pre>
512      *
513      * The value 'age' is the same as the value 'v'.
514      *
515      * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
516      * subtract from
517      * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
518      * subtract off the minuend
519      * @return the difference in the units of this field
520      */

521     public int getDifference(long minuendInstant, long subtrahendInstant) {
522         return getDurationField().getDifference(minuendInstant, subtrahendInstant);
523     }
524
525     /**
526      * Computes the difference between two instants, as measured in the units
527      * of this field. Any fractional units are dropped from the result. Calling
528      * getDifference reverses the effect of calling add. In the following code:
529      *
530      * <pre>
531      * long instant = ...
532      * long v = ...
533      * long age = getDifferenceAsLong(add(instant, v), instant);
534      * </pre>
535      *
536      * The value 'age' is the same as the value 'v'.
537      *
538      * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
539      * subtract from
540      * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
541      * subtract off the minuend
542      * @return the difference in the units of this field
543      */

544     public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
545         return getDurationField().getDifferenceAsLong(minuendInstant, subtrahendInstant);
546     }
547
548     /**
549      * Sets a value in the milliseconds supplied.
550      * <p>
551      * The value of this field will be set.
552      * If the value is invalid, an exception if thrown.
553      * <p>
554      * If setting this field would make other fields invalid, then those fields
555      * may be changed. For example if the current date is the 31st January, and
556      * the month is set to February, the day would be invalid. Instead, the day
557      * would be changed to the closest value - the 28th/29th February as appropriate.
558      *
559      * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in
560      * @param value the value to set, in the units of the field
561      * @return the updated milliseconds
562      * @throws IllegalArgumentException if the value is invalid
563      */

564     public abstract long set(long instant, int value);
565
566     /**
567      * Sets a value using the specified partial instant.
568      * <p>
569      * The value of this field (specified by the index) will be set.
570      * If the value is invalid, an exception if thrown.
571      * <p>
572      * If setting this field would make other fields invalid, then those fields
573      * may be changed. For example if the current date is the 31st January, and
574      * the month is set to February, the day would be invalid. Instead, the day
575      * would be changed to the closest value - the 28th/29th February as appropriate.
576      *
577      * @param partial the partial instant
578      * @param fieldIndex the index of this field in the instant
579      * @param values the values to update
580      * @param newValue the value to set, in the units of the field
581      * @return the updated values
582      * @throws IllegalArgumentException if the value is invalid
583      */

584     public int[] set(ReadablePartial partial, int fieldIndex, int[] values, int newValue) {
585         FieldUtils.verifyValueBounds(this, newValue, getMinimumValue(partial, values), getMaximumValue(partial, values));
586         values[fieldIndex] = newValue;
587         
588         // may need to adjust smaller fields
589
for (int i = fieldIndex + 1; i < partial.size(); i++) {
590             DateTimeField field = partial.getField(i);
591             if (values[i] > field.getMaximumValue(partial, values)) {
592                 values[i] = field.getMaximumValue(partial, values);
593             }
594             if (values[i] < field.getMinimumValue(partial, values)) {
595                 values[i] = field.getMinimumValue(partial, values);
596             }
597         }
598         return values;
599     }
600
601     /**
602      * Sets a value in the milliseconds supplied from a human-readable, text value.
603      * If the specified locale is null, the default locale is used.
604      * <p>
605      * This implementation uses <code>convertText(String, Locale)</code> and
606      * {@link #set(long, int)}.
607      * <p>
608      * Note: subclasses that override this method should also override
609      * getAsText.
610      *
611      * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in
612      * @param text the text value to set
613      * @param locale the locale to use for selecting a text symbol, null for default
614      * @return the updated milliseconds
615      * @throws IllegalArgumentException if the text value is invalid
616      */

617     public long set(long instant, String JavaDoc text, Locale JavaDoc locale) {
618         int value = convertText(text, locale);
619         return set(instant, value);
620     }
621
622     /**
623      * Sets a value in the milliseconds supplied from a human-readable, text value.
624      * <p>
625      * This implementation uses {@link #set(long, String, Locale)}.
626      * <p>
627      * Note: subclasses that override this method should also override getAsText.
628      *
629      * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in
630      * @param text the text value to set
631      * @return the updated milliseconds
632      * @throws IllegalArgumentException if the text value is invalid
633      */

634     public final long set(long instant, String JavaDoc text) {
635         return set(instant, text, null);
636     }
637
638     /**
639      * Sets a value in the milliseconds supplied from a human-readable, text value.
640      * If the specified locale is null, the default locale is used.
641      * <p>
642      * This implementation uses <code>convertText(String, Locale)</code> and
643      * {@link #set(ReadablePartial, int, int[], int)}.
644      *
645      * @param instant the partial instant
646      * @param fieldIndex the index of this field in the instant
647      * @param values the values of the partial instant which should be updated
648      * @param text the text value to set
649      * @param locale the locale to use for selecting a text symbol, null for default
650      * @return the passed in values
651      * @throws IllegalArgumentException if the text value is invalid
652      */

653     public int[] set(ReadablePartial instant, int fieldIndex, int[] values, String JavaDoc text, Locale JavaDoc locale) {
654         int value = convertText(text, locale);
655         return set(instant, fieldIndex, values, value);
656     }
657
658     /**
659      * Convert the specified text and locale into a value.
660      *
661      * @param text the text to convert
662      * @param locale the locale to convert using
663      * @return the value extracted from the text
664      * @throws IllegalArgumentException if the text is invalid
665      */

666     protected int convertText(String JavaDoc text, Locale JavaDoc locale) {
667         try {
668             return Integer.parseInt(text);
669         } catch (NumberFormatException JavaDoc ex) {
670             throw new IllegalFieldValueException(getType(), text);
671         }
672     }
673
674     // Extra information API
675
//------------------------------------------------------------------------
676
/**
677      * Returns the duration per unit value of this field. For example, if this
678      * field represents "hour of day", then the unit duration is an hour.
679      *
680      * @return the duration of this field, or UnsupportedDurationField if field
681      * has no duration
682      */

683     public abstract DurationField getDurationField();
684
685     /**
686      * Returns the range duration of this field. For example, if this field
687      * represents "hour of day", then the range duration is a day.
688      *
689      * @return the range duration of this field, or null if field has no range
690      */

691     public abstract DurationField getRangeDurationField();
692
693     /**
694      * Returns whether this field is 'leap' for the specified instant.
695      * <p>
696      * For example, a leap year would return true, a non leap year would return
697      * false.
698      * <p>
699      * This implementation returns false.
700      *
701      * @return true if the field is 'leap'
702      */

703     public boolean isLeap(long instant) {
704         return false;
705     }
706
707     /**
708      * Gets the amount by which this field is 'leap' for the specified instant.
709      * <p>
710      * For example, a leap year would return one, a non leap year would return
711      * zero.
712      * <p>
713      * This implementation returns zero.
714      */

715     public int getLeapAmount(long instant) {
716         return 0;
717     }
718
719     /**
720      * If this field were to leap, then it would be in units described by the
721      * returned duration. If this field doesn't ever leap, null is returned.
722      * <p>
723      * This implementation returns null.
724      */

725     public DurationField getLeapDurationField() {
726         return null;
727     }
728
729     /**
730      * Get the minimum allowable value for this field.
731      *
732      * @return the minimum valid value for this field, in the units of the
733      * field
734      */

735     public abstract int getMinimumValue();
736
737     /**
738      * Get the minimum value for this field evaluated at the specified time.
739      * <p>
740      * This implementation returns the same as {@link #getMinimumValue()}.
741      *
742      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
743      * @return the minimum value for this field, in the units of the field
744      */

745     public int getMinimumValue(long instant) {
746         return getMinimumValue();
747     }
748
749     /**
750      * Get the minimum value for this field evaluated at the specified instant.
751      * <p>
752      * This implementation returns the same as {@link #getMinimumValue()}.
753      *
754      * @param instant the partial instant to query
755      * @return the minimum value for this field, in the units of the field
756      */

757     public int getMinimumValue(ReadablePartial instant) {
758         return getMinimumValue();
759     }
760
761     /**
762      * Get the minimum value for this field using the partial instant and
763      * the specified values.
764      * <p>
765      * This implementation returns the same as {@link #getMinimumValue(ReadablePartial)}.
766      *
767      * @param instant the partial instant to query
768      * @param values the values to use
769      * @return the minimum value for this field, in the units of the field
770      */

771     public int getMinimumValue(ReadablePartial instant, int[] values) {
772         return getMinimumValue(instant);
773     }
774
775     /**
776      * Get the maximum allowable value for this field.
777      *
778      * @return the maximum valid value for this field, in the units of the
779      * field
780      */

781     public abstract int getMaximumValue();
782
783     /**
784      * Get the maximum value for this field evaluated at the specified time.
785      * <p>
786      * This implementation returns the same as {@link #getMaximumValue()}.
787      *
788      * @param instant the milliseconds from 1970-01-01T00:00:00Z to query
789      * @return the maximum value for this field, in the units of the field
790      */

791     public int getMaximumValue(long instant) {
792         return getMaximumValue();
793     }
794
795     /**
796      * Get the maximum value for this field evaluated at the specified instant.
797      * <p>
798      * This implementation returns the same as {@link #getMaximumValue()}.
799      *
800      * @param instant the partial instant to query
801      * @return the maximum value for this field, in the units of the field
802      */

803     public int getMaximumValue(ReadablePartial instant) {
804         return getMaximumValue();
805     }
806
807     /**
808      * Get the maximum value for this field using the partial instant and
809      * the specified values.
810      * <p>
811      * This implementation returns the same as {@link #getMaximumValue(ReadablePartial)}.
812      *
813      * @param instant the partial instant to query
814      * @param values the values to use
815      * @return the maximum value for this field, in the units of the field
816      */

817     public int getMaximumValue(ReadablePartial instant, int[] values) {
818         return getMaximumValue(instant);
819     }
820
821     /**
822      * Get the maximum text value for this field. The default implementation
823      * returns the equivalent of Integer.toString(getMaximumValue()).length().
824      *
825      * @param locale the locale to use for selecting a text symbol
826      * @return the maximum text length
827      */

828     public int getMaximumTextLength(Locale JavaDoc locale) {
829         int max = getMaximumValue();
830         if (max >= 0) {
831             if (max < 10) {
832                 return 1;
833             } else if (max < 100) {
834                 return 2;
835             } else if (max < 1000) {
836                 return 3;
837             }
838         }
839         return Integer.toString(max).length();
840     }
841
842     /**
843      * Get the maximum short text value for this field. The default
844      * implementation returns getMaximumTextLength().
845      *
846      * @param locale the locale to use for selecting a text symbol
847      * @return the maximum short text length
848      */

849     public int getMaximumShortTextLength(Locale JavaDoc locale) {
850         return getMaximumTextLength(locale);
851     }
852
853     // Calculation API
854
//------------------------------------------------------------------------
855
/**
856      * Round to the lowest whole unit of this field. After rounding, the value
857      * of this field and all fields of a higher magnitude are retained. The
858      * fractional millis that cannot be expressed in whole increments of this
859      * field are set to minimum.
860      * <p>
861      * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the
862      * lowest whole hour is 2002-11-02T23:00:00.000.
863      *
864      * @param instant the milliseconds from 1970-01-01T00:00:00Z to round
865      * @return rounded milliseconds
866      */

867     public abstract long roundFloor(long instant);
868
869     /**
870      * Round to the highest whole unit of this field. The value of this field
871      * and all fields of a higher magnitude may be incremented in order to
872      * achieve this result. The fractional millis that cannot be expressed in
873      * whole increments of this field are set to minimum.
874      * <p>
875      * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the
876      * highest whole hour is 2002-11-03T00:00:00.000.
877      * <p>
878      * The default implementation calls roundFloor, and if the instant is
879      * modified as a result, adds one field unit. Subclasses are encouraged to
880      * provide a more efficient implementation.
881      *
882      * @param instant the milliseconds from 1970-01-01T00:00:00Z to round
883      * @return rounded milliseconds
884      */

885     public long roundCeiling(long instant) {
886         long newInstant = roundFloor(instant);
887         if (newInstant != instant) {
888             instant = add(newInstant, 1);
889         }
890         return instant;
891     }
892
893     /**
894      * Round to the nearest whole unit of this field. If the given millisecond
895      * value is closer to the floor or is exactly halfway, this function
896      * behaves like roundFloor. If the millisecond value is closer to the
897      * ceiling, this function behaves like roundCeiling.
898      *
899      * @param instant the milliseconds from 1970-01-01T00:00:00Z to round
900      * @return rounded milliseconds
901      */

902     public long roundHalfFloor(long instant) {
903         long floor = roundFloor(instant);
904         long ceiling = roundCeiling(instant);
905
906         long diffFromFloor = instant - floor;
907         long diffToCeiling = ceiling - instant;
908
909         if (diffFromFloor <= diffToCeiling) {
910             // Closer to the floor, or halfway - round floor
911
return floor;
912         } else {
913             return ceiling;
914         }
915     }
916
917     /**
918      * Round to the nearest whole unit of this field. If the given millisecond
919      * value is closer to the floor, this function behaves like roundFloor. If
920      * the millisecond value is closer to the ceiling or is exactly halfway,
921      * this function behaves like roundCeiling.
922      *
923      * @param instant the milliseconds from 1970-01-01T00:00:00Z to round
924      * @return rounded milliseconds
925      */

926     public long roundHalfCeiling(long instant) {
927         long floor = roundFloor(instant);
928         long ceiling = roundCeiling(instant);
929
930         long diffFromFloor = instant - floor;
931         long diffToCeiling = ceiling - instant;
932
933         if (diffToCeiling <= diffFromFloor) {
934             // Closer to the ceiling, or halfway - round ceiling
935
return ceiling;
936         } else {
937             return floor;
938         }
939     }
940
941     /**
942      * Round to the nearest whole unit of this field. If the given millisecond
943      * value is closer to the floor, this function behaves like roundFloor. If
944      * the millisecond value is closer to the ceiling, this function behaves
945      * like roundCeiling.
946      * <p>
947      * If the millisecond value is exactly halfway between the floor and
948      * ceiling, the ceiling is chosen over the floor only if it makes this
949      * field's value even.
950      *
951      * @param instant the milliseconds from 1970-01-01T00:00:00Z to round
952      * @return rounded milliseconds
953      */

954     public long roundHalfEven(long instant) {
955         long floor = roundFloor(instant);
956         long ceiling = roundCeiling(instant);
957
958         long diffFromFloor = instant - floor;
959         long diffToCeiling = ceiling - instant;
960
961         if (diffFromFloor < diffToCeiling) {
962             // Closer to the floor - round floor
963
return floor;
964         } else if (diffToCeiling < diffFromFloor) {
965             // Closer to the ceiling - round ceiling
966
return ceiling;
967         } else {
968             // Round to the instant that makes this field even. If both values
969
// make this field even (unlikely), favor the ceiling.
970
if ((get(ceiling) & 1) == 0) {
971                 return ceiling;
972             }
973             return floor;
974         }
975     }
976
977     /**
978      * Returns the fractional duration milliseconds of this field. In other
979      * words, calling remainder returns the duration that roundFloor would
980      * subtract.
981      * <p>
982      * For example, on a datetime of 2002-11-02T23:34:56.789, the remainder by
983      * hour is 34 minutes and 56.789 seconds.
984      * <p>
985      * The default implementation computes
986      * <code>instant - roundFloor(instant)</code>. Subclasses are encouraged to
987      * provide a more efficient implementation.
988      *
989      * @param instant the milliseconds from 1970-01-01T00:00:00Z to get the
990      * remainder
991      * @return remainder duration, in milliseconds
992      */

993     public long remainder(long instant) {
994         return instant - roundFloor(instant);
995     }
996
997     /**
998      * Get a suitable debug string.
999      *
1000     * @return debug string
1001     */

1002    public String JavaDoc toString() {
1003        return "DateTimeField[" + getName() + ']';
1004    }
1005
1006}
1007
Popular Tags