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;
17  
18  import java.util.Locale;
19  
20  /**
21   * Defines the calculation engine for date and time fields.
22   * The interface defines a set of methods that manipulate a millisecond datetime
23   * with regards to a single field, such as monthOfYear or secondOfMinute.
24   * <p>
25   * This design is extensible so, if you wish, you can extract a different field from
26   * the milliseconds. A number of standard implementations are provided to assist.
27   *
28   * @author Guy Allard
29   * @author Stephen Colebourne
30   * @author Brian S O'Neill
31   * @since 1.0
32   */
33  public abstract class DateTimeField {
34  
35      /**
36       * Get the type of the field.
37       * 
38       * @return field type
39       */
40      public abstract DateTimeFieldType getType();
41  
42      /**
43       * Get the name of the field.
44       * <p>
45       * By convention, names follow a pattern of "dddOfRrr", where "ddd" represents
46       * the (singular) duration unit field name and "Rrr" represents the (singular)
47       * duration range field name. If the range field is not applicable, then
48       * the name of the field is simply the (singular) duration field name.
49       * 
50       * @return field name
51       */
52      public abstract String getName();
53  
54      /**
55       * Returns true if this field is supported.
56       * 
57       * @return true if this field is supported
58       */
59      public abstract boolean isSupported();
60  
61      /**
62       * Returns true if the set method is lenient. If so, it accepts values that
63       * are out of bounds. For example, a lenient day of month field accepts 32
64       * for January, converting it to February 1.
65       * 
66       * @return true if this field is lenient
67       */
68      public abstract boolean isLenient();
69  
70      // Main access API
71      //------------------------------------------------------------------------
72      /**
73       * Get the value of this field from the milliseconds.
74       * 
75       * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
76       * @return the value of the field, in the units of the field
77       */
78      public abstract int get(long instant);
79  
80      /**
81       * Get the human-readable, text value of this field from the milliseconds.
82       * If the specified locale is null, the default locale is used.
83       *
84       * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
85       * @param locale the locale to use for selecting a text symbol, null for default
86       * @return the text value of the field
87       */
88      public abstract String getAsText(long instant, Locale locale);
89  
90      /**
91       * Get the human-readable, text value of this field from the milliseconds.
92       * 
93       * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
94       * @return the text value of the field
95       */
96      public abstract String getAsText(long instant);
97  
98      /**
99       * Get the human-readable, text value of this field from a partial instant.
100      * If the specified locale is null, the default locale is used.
101      *
102      * @param partial  the partial instant to query
103      * @param fieldValue  the field value of this field, provided for performance
104      * @param locale  the locale to use for selecting a text symbol, null for default
105      * @return the text value of the field
106      */
107     public abstract String getAsText(ReadablePartial partial, int fieldValue, Locale locale);
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      *
113      * @param partial  the partial instant to query
114      * @param locale  the locale to use for selecting a text symbol, null for default
115      * @return the text value of the field
116      */
117     public abstract String getAsText(ReadablePartial partial, Locale locale);
118 
119     /**
120      * Get the human-readable, text value of this field from the field value.
121      * If the specified locale is null, the default locale is used.
122      *
123      * @param fieldValue  the numeric value to convert to text
124      * @param locale the locale to use for selecting a text symbol, null for default
125      * @return the text value of the field
126      */
127     public abstract String getAsText(int fieldValue, Locale locale);
128 
129     /**
130      * Get the human-readable, short text value of this field from the
131      * milliseconds.  If the specified locale is null, the default locale is used.
132      *
133      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
134      * @param locale the locale to use for selecting a text symbol, null for default
135      * @return the short text value of the field
136      */
137     public abstract String getAsShortText(long instant, Locale locale);
138 
139     /**
140      * Get the human-readable, short text value of this field from the
141      * milliseconds.
142      * 
143      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
144      * @return the short text value of the field
145      */
146     public abstract String getAsShortText(long instant);
147 
148     /**
149      * Get the human-readable, short text value of this field from a partial instant.
150      * If the specified locale is null, the default locale is used.
151      *
152      * @param partial  the partial instant to query
153      * @param fieldValue  the field value of this field, provided for performance
154      * @param locale  the locale to use for selecting a text symbol, null for default
155      * @return the text value of the field
156      */
157     public abstract String getAsShortText(ReadablePartial partial, int fieldValue, Locale locale);
158 
159     /**
160      * Get the human-readable, short text value of this field from a partial instant.
161      * If the specified locale is null, the default locale is used.
162      *
163      * @param partial  the partial instant to query
164      * @param locale  the locale to use for selecting a text symbol, null for default
165      * @return the text value of the field
166      */
167     public abstract String getAsShortText(ReadablePartial partial, Locale locale);
168 
169     /**
170      * Get the human-readable, short text value of this field from the field value.
171      * If the specified locale is null, the default locale is used.
172      *
173      * @param fieldValue  the numeric value to convert to text
174      * @param locale the locale to use for selecting a text symbol, null for default
175      * @return the text value of the field
176      */
177     public abstract String getAsShortText(int fieldValue, Locale locale);
178 
179     /**
180      * Adds a value (which may be negative) to the millis value,
181      * overflowing into larger fields if necessary.
182      * <p>
183      * The value will be added to this field. If the value is too large to be
184      * added solely to this field, larger fields will increase as required.
185      * Smaller fields should be unaffected, except where the result would be
186      * an invalid value for a smaller field. In this case the smaller field is
187      * adjusted to be in range.
188      * <p>
189      * For example, in the ISO chronology:<br>
190      * 2000-08-20 add six months is 2001-02-20<br>
191      * 2000-08-20 add twenty months is 2002-04-20<br>
192      * 2000-08-20 add minus nine months is 1999-11-20<br>
193      * 2001-01-31 add one month  is 2001-02-28<br>
194      * 2001-01-31 add two months is 2001-03-31<br>
195      * 
196      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to add to
197      * @param value  the value to add, in the units of the field
198      * @return the updated milliseconds
199      */
200     public abstract long add(long instant, int value);
201 
202     /**
203      * Adds a value (which may be negative) to the millis value,
204      * overflowing into larger fields if necessary.
205      * 
206      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to add to
207      * @param value  the long value to add, in the units of the field
208      * @return the updated milliseconds
209      * @throws IllegalArgumentException if value is too large
210      * @see #add(long,int)
211      */
212     public abstract long add(long instant, long value);
213 
214     /**
215      * Adds a value (which may be negative) to the partial instant,
216      * throwing an exception if the maximum size of the instant is reached.
217      * <p>
218      * The value will be added to this field, overflowing into larger fields
219      * if necessary. Smaller fields should be unaffected, except where the
220      * result would be an invalid value for a smaller field. In this case the
221      * smaller field is adjusted to be in range.
222      * <p>
223      * Partial instants only contain some fields. This may result in a maximum
224      * possible value, such as TimeOfDay being limited to 23:59:59:999. If this
225      * limit is breached by the add an exception is thrown.
226      * <p>
227      * For example, in the ISO chronology:<br>
228      * 2000-08-20 add six months is 2000-02-20<br>
229      * 2000-08-20 add twenty months is 2000-04-20<br>
230      * 2000-08-20 add minus nine months is 2000-11-20<br>
231      * 2001-01-31 add one month  is 2001-02-28<br>
232      * 2001-01-31 add two months is 2001-03-31<br>
233      * 
234      * @param instant  the partial instant
235      * @param fieldIndex  the index of this field in the instant
236      * @param values  the values of the partial instant which should be updated
237      * @param valueToAdd  the value to add, in the units of the field
238      * @return the passed in values
239      * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached
240      */
241     public abstract int[] add(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd);
242 
243     /**
244      * Adds a value (which may be negative) to the partial instant,
245      * wrapping the whole partial if the maximum size of the partial is reached.
246      * <p>
247      * The value will be added to this field, overflowing into larger fields
248      * if necessary. Smaller fields should be unaffected, except where the
249      * result would be an invalid value for a smaller field. In this case the
250      * smaller field is adjusted to be in range.
251      * <p>
252      * Partial instants only contain some fields. This may result in a maximum
253      * possible value, such as TimeOfDay normally being limited to 23:59:59:999.
254      * If ths limit is reached by the addition, this method will wrap back to
255      * 00:00:00.000. In fact, you would generally only use this method for
256      * classes that have a limitation such as this.
257      * <p>
258      * For example, in the ISO chronology:<br>
259      * 10:20:30 add 20 minutes is 10:40:30<br>
260      * 10:20:30 add 45 minutes is 11:05:30<br>
261      * 10:20:30 add 16 hours is 02:20:30<br>
262      * 
263      * @param instant  the partial instant
264      * @param fieldIndex  the index of this field in the partial
265      * @param values  the values of the partial instant which should be updated
266      * @param valueToAdd  the value to add, in the units of the field
267      * @return the passed in values
268      * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached
269      */
270     public abstract int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd);
271 
272     /**
273      * Adds a value (which may be negative) to the millis value,
274      * wrapping within this field.
275      * <p>
276      * The value will be added to this field. If the value is too large to be
277      * added solely to this field then it wraps. Larger fields are always
278      * unaffected. Smaller fields should be unaffected, except where the
279      * result would be an invalid value for a smaller field. In this case the
280      * smaller field is adjusted to be in range.
281      * <p>
282      * For example, in the ISO chronology:<br>
283      * 2000-08-20 addWrapField six months is 2000-02-20<br>
284      * 2000-08-20 addWrapField twenty months is 2000-04-20<br>
285      * 2000-08-20 addWrapField minus nine months is 2000-11-20<br>
286      * 2001-01-31 addWrapField one month  is 2001-02-28<br>
287      * 2001-01-31 addWrapField two months is 2001-03-31<br>
288      * 
289      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to add to
290      * @param value  the value to add, in the units of the field
291      * @return the updated milliseconds
292      */
293     public abstract long addWrapField(long instant, int value) ;
294 
295     /**
296      * Adds a value (which may be negative) to the partial instant,
297      * wrapping within this field.
298      * <p>
299      * The value will be added to this field. If the value is too large to be
300      * added solely to this field then it wraps. Larger fields are always
301      * unaffected. Smaller fields should be unaffected, except where the
302      * result would be an invalid value for a smaller field. In this case the
303      * smaller field is adjusted to be in range.
304      * <p>
305      * For example, in the ISO chronology:<br>
306      * 2000-08-20 addWrapField six months is 2000-02-20<br>
307      * 2000-08-20 addWrapField twenty months is 2000-04-20<br>
308      * 2000-08-20 addWrapField minus nine months is 2000-11-20<br>
309      * 2001-01-31 addWrapField one month  is 2001-02-28<br>
310      * 2001-01-31 addWrapField two months is 2001-03-31<br>
311      * 
312      * @param instant  the partial instant
313      * @param fieldIndex  the index of this field in the instant
314      * @param values  the values of the partial instant which should be updated
315      * @param valueToAdd  the value to add, in the units of the field
316      * @return the passed in values
317      * @throws IllegalArgumentException if the value is invalid
318      */
319     public abstract int[] addWrapField(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd);
320 
321     /**
322      * Computes the difference between two instants, as measured in the units
323      * of this field. Any fractional units are dropped from the result. Calling
324      * getDifference reverses the effect of calling add. In the following code:
325      *
326      * <pre>
327      * long instant = ...
328      * int v = ...
329      * int age = getDifference(add(instant, v), instant);
330      * </pre>
331      *
332      * The value 'age' is the same as the value 'v'.
333      *
334      * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
335      * subtract from
336      * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
337      * subtract off the minuend
338      * @return the difference in the units of this field
339      */
340     public abstract int getDifference(long minuendInstant, long subtrahendInstant);
341 
342     /**
343      * Computes the difference between two instants, as measured in the units
344      * of this field. Any fractional units are dropped from the result. Calling
345      * getDifference reverses the effect of calling add. In the following code:
346      *
347      * <pre>
348      * long instant = ...
349      * long v = ...
350      * long age = getDifferenceAsLong(add(instant, v), instant);
351      * </pre>
352      *
353      * The value 'age' is the same as the value 'v'.
354      *
355      * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
356      * subtract from
357      * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
358      * subtract off the minuend
359      * @return the difference in the units of this field
360      */
361     public abstract long getDifferenceAsLong(long minuendInstant, long subtrahendInstant);
362 
363     /**
364      * Sets a value in the milliseconds supplied.
365      * <p>
366      * The value of this field will be set.
367      * If the value is invalid, an exception if thrown.
368      * <p>
369      * If setting this field would make other fields invalid, then those fields
370      * may be changed. For example if the current date is the 31st January, and
371      * the month is set to February, the day would be invalid. Instead, the day
372      * would be changed to the closest value - the 28th/29th February as appropriate.
373      * 
374      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to set in
375      * @param value  the value to set, in the units of the field
376      * @return the updated milliseconds
377      * @throws IllegalArgumentException if the value is invalid
378      */
379     public abstract long set(long instant, int value);
380 
381     /**
382      * Sets a value using the specified partial instant.
383      * <p>
384      * The value of this field (specified by the index) will be set.
385      * If the value is invalid, an exception if thrown.
386      * <p>
387      * If setting this field would make other fields invalid, then those fields
388      * may be changed. For example if the current date is the 31st January, and
389      * the month is set to February, the day would be invalid. Instead, the day
390      * would be changed to the closest value - the 28th/29th February as appropriate.
391      * 
392      * @param instant  the partial instant
393      * @param fieldIndex  the index of this field in the instant
394      * @param values  the values of the partial instant which should be updated
395      * @param newValue  the value to set, in the units of the field
396      * @return the passed in values
397      * @throws IllegalArgumentException if the value is invalid
398      */
399     public abstract int[] set(ReadablePartial instant, int fieldIndex, int[] values, int newValue);
400 
401     /**
402      * Sets a value in the milliseconds supplied from a human-readable, text value.
403      * If the specified locale is null, the default locale is used.
404      * <p>
405      * If setting this field would make other fields invalid, then those fields
406      * may be changed. For example if the current date is the 31st January, and
407      * the month is set to February, the day would be invalid. Instead, the day
408      * would be changed to the closest value - the 28th/29th February as appropriate.
409      *
410      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to set in
411      * @param text  the text value to set
412      * @param locale the locale to use for selecting a text symbol, null for default
413      * @return the updated milliseconds
414      * @throws IllegalArgumentException if the text value is invalid
415      */
416     public abstract long set(long instant, String text, Locale locale);
417 
418     /**
419      * Sets a value in the milliseconds supplied from a human-readable, text value.
420      * <p>
421      * If setting this field would make other fields invalid, then those fields
422      * may be changed. For example if the current date is the 31st January, and
423      * the month is set to February, the day would be invalid. Instead, the day
424      * would be changed to the closest value - the 28th/29th February as appropriate.
425      * 
426      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to set in
427      * @param text  the text value to set
428      * @return the updated milliseconds
429      * @throws IllegalArgumentException if the text value is invalid
430      */
431     public abstract long set(long instant, String text);
432 
433     /**
434      * Sets a value in the milliseconds supplied from a human-readable, text value.
435      * If the specified locale is null, the default locale is used.
436      * <p>
437      * If setting this field would make other fields invalid, then those fields
438      * may be changed. For example if the current date is the 31st January, and
439      * the month is set to February, the day would be invalid. Instead, the day
440      * would be changed to the closest value - the 28th/29th February as appropriate.
441      *
442      * @param instant  the partial instant
443      * @param fieldIndex  the index of this field in the instant
444      * @param values  the values of the partial instant which should be updated
445      * @param text  the text value to set
446      * @param locale the locale to use for selecting a text symbol, null for default
447      * @return the passed in values
448      * @throws IllegalArgumentException if the text value is invalid
449      */
450     public abstract int[] set(ReadablePartial instant, int fieldIndex, int[] values, String text, Locale locale);
451 
452     // Extra information API
453     //------------------------------------------------------------------------
454     /**
455      * Returns the duration per unit value of this field. For example, if this
456      * field represents "hour of day", then the duration is an hour.
457      *
458      * @return the duration of this field, or UnsupportedDurationField if field
459      * has no duration
460      */
461     public abstract DurationField getDurationField();
462 
463     /**
464      * Returns the range duration of this field. For example, if this field
465      * represents "hour of day", then the range duration is a day.
466      *
467      * @return the range duration of this field, or null if field has no range
468      */
469     public abstract DurationField getRangeDurationField();
470 
471     /**
472      * Returns whether this field is 'leap' for the specified instant.
473      * <p>
474      * For example, a leap year would return true, a non leap year would return
475      * false.
476      * 
477      * @param instant  the instant to check for leap status
478      * @return true if the field is 'leap'
479      */
480     public abstract boolean isLeap(long instant);
481 
482     /**
483      * Gets the amount by which this field is 'leap' for the specified instant.
484      * <p>
485      * For example, a leap year would return one, a non leap year would return
486      * zero.
487      * 
488      * @param instant  the instant to check for leap status
489      * @return the amount, in units of the leap duration field, that the field is leap
490      */
491     public abstract int getLeapAmount(long instant);
492 
493     /**
494      * If this field were to leap, then it would be in units described by the
495      * returned duration. If this field doesn't ever leap, null is returned.
496      * 
497      * @return the leap duration field if field can be leap, null if it can't
498      */
499     public abstract DurationField getLeapDurationField();
500 
501     /**
502      * Get the minimum allowable value for this field.
503      * 
504      * @return the minimum valid value for this field, in the units of the
505      * field
506      */
507     public abstract int getMinimumValue();
508 
509     /**
510      * Get the minimum value for this field evaluated at the specified time.
511      * 
512      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
513      * @return the minimum value for this field, in the units of the field
514      */
515     public abstract int getMinimumValue(long instant);
516 
517     /**
518      * Get the minimum value for this field evaluated at the specified time.
519      * 
520      * @param instant  the partial instant to query
521      * @return the minimum value for this field, in the units of the field
522      */
523     public abstract int getMinimumValue(ReadablePartial instant);
524 
525     /**
526      * Get the minimum value for this field using the partial instant and
527      * the specified values.
528      * 
529      * @param instant  the partial instant to query
530      * @param values  the values to use
531      * @return the minimum value for this field, in the units of the field
532      */
533     public abstract int getMinimumValue(ReadablePartial instant, int[] values);
534 
535     /**
536      * Get the maximum allowable value for this field.
537      * 
538      * @return the maximum valid value for this field, in the units of the
539      * field
540      */
541     public abstract int getMaximumValue();
542 
543     /**
544      * Get the maximum value for this field evaluated at the specified time.
545      * 
546      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to query
547      * @return the maximum value for this field, in the units of the field
548      */
549     public abstract int getMaximumValue(long instant);
550 
551     /**
552      * Get the maximum value for this field evaluated at the specified time.
553      * 
554      * @param instant  the partial instant to query
555      * @return the maximum value for this field, in the units of the field
556      */
557     public abstract int getMaximumValue(ReadablePartial instant);
558 
559     /**
560      * Get the maximum value for this field using the partial instant and
561      * the specified values.
562      * 
563      * @param instant  the partial instant to query
564      * @param values  the values to use
565      * @return the maximum value for this field, in the units of the field
566      */
567     public abstract int getMaximumValue(ReadablePartial instant, int[] values);
568 
569     /**
570      * Get the maximum text value for this field.
571      * 
572      * @param locale  the locale to use for selecting a text symbol
573      * @return the maximum text length
574      */
575     public abstract int getMaximumTextLength(Locale locale);
576 
577     /**
578      * Get the maximum short text value for this field.
579      * 
580      * @param locale  the locale to use for selecting a text symbol
581      * @return the maximum short text length
582      */
583     public abstract int getMaximumShortTextLength(Locale locale);
584 
585     // Calculation API
586     //------------------------------------------------------------------------
587     /**
588      * Round to the lowest whole unit of this field. After rounding, the value
589      * of this field and all fields of a higher magnitude are retained. The
590      * fractional millis that cannot be expressed in whole increments of this
591      * field are set to minimum.
592      * <p>
593      * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the
594      * lowest whole hour is 2002-11-02T23:00:00.000.
595      *
596      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
597      * @return rounded milliseconds
598      */
599     public abstract long roundFloor(long instant);
600 
601     /**
602      * Round to the highest whole unit of this field. The value of this field
603      * and all fields of a higher magnitude may be incremented in order to
604      * achieve this result. The fractional millis that cannot be expressed in
605      * whole increments of this field are set to minimum.
606      * <p>
607      * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the
608      * highest whole hour is 2002-11-03T00:00:00.000.
609      *
610      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
611      * @return rounded milliseconds
612      */
613     public abstract long roundCeiling(long instant);
614 
615     /**
616      * Round to the nearest whole unit of this field. If the given millisecond
617      * value is closer to the floor or is exactly halfway, this function
618      * behaves like roundFloor. If the millisecond value is closer to the
619      * ceiling, this function behaves like roundCeiling.
620      *
621      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
622      * @return rounded milliseconds
623      */
624     public abstract long roundHalfFloor(long instant);
625 
626     /**
627      * Round to the nearest whole unit of this field. If the given millisecond
628      * value is closer to the floor, this function behaves like roundFloor. If
629      * the millisecond value is closer to the ceiling or is exactly halfway,
630      * this function behaves like roundCeiling.
631      *
632      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
633      * @return rounded milliseconds
634      */
635     public abstract long roundHalfCeiling(long instant);
636 
637     /**
638      * Round to the nearest whole unit of this field. If the given millisecond
639      * value is closer to the floor, this function behaves like roundFloor. If
640      * the millisecond value is closer to the ceiling, this function behaves
641      * like roundCeiling.
642      * <p>
643      * If the millisecond value is exactly halfway between the floor and
644      * ceiling, the ceiling is chosen over the floor only if it makes this
645      * field's value even.
646      *
647      * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
648      * @return rounded milliseconds
649      */
650     public abstract long roundHalfEven(long instant);
651 
652     /**
653      * Returns the fractional duration milliseconds of this field. In other
654      * words, calling remainder returns the duration that roundFloor would
655      * subtract.
656      * <p>
657      * For example, on a datetime of 2002-11-02T23:34:56.789, the remainder by
658      * hour is 34 minutes and 56.789 seconds.
659      *
660      * @param instant the milliseconds from 1970-01-01T00:00:00Z to get the
661      * remainder
662      * @return remainder duration, in milliseconds
663      */
664     public abstract long remainder(long instant);
665 
666     /**
667      * Get a suitable debug string.
668      * 
669      * @return debug string
670      */
671     public abstract String toString();
672     
673 }