View Javadoc

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;
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("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 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 getAsText(long instant, Locale 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 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 getAsText(ReadablePartial partial, int fieldValue, Locale 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 getAsText(ReadablePartial partial, Locale 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 getAsText(int fieldValue, Locale 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 getAsShortText(long instant, Locale 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 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 getAsShortText(ReadablePartial partial, int fieldValue, Locale 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 getAsShortText(ReadablePartial partial, Locale 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 getAsShortText(int fieldValue, Locale 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("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("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("Maximum value exceeded for add");
337                 }
338                 nextField = instant.getField(fieldIndex - 1);
339                 if (getRangeDurationField().getType() != nextField.getDurationField().getType()) {
340                     throw new IllegalArgumentException("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("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("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 text, Locale 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 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 text, Locale 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 text, Locale locale) {
667         try {
668             return Integer.parseInt(text);
669         } catch (NumberFormatException 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 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 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 toString() {
1003         return "DateTimeField[" + getName() + ']';
1004     }
1005 
1006 }