001    package time;
002    
003    import java.util.*;
004    
005    /*
006     * Copyleft notice: This is public-domain software and documentation
007     * with no restrictions of any kind.
008     * Please feel free to use any of it in any way you want.
009     * This work is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
012     */
013    
014    /**
015     * This class represents a system used by humans to describe time.
016     *
017     * <p>
018     * A chronology provides several <tt>TimeField</tt> that have a meaning in this chronology.
019     * One can merge several <tt>TimeField</tt> to create <tt>TimeMask</tt>
020     * objects.
021     *
022     * <p>
023     * Those <tt>TimeMask</tt> objects define <i>time format</i> that can be used to
024     * describe a precise <tt>Time</tt> object.
025     *
026     * <p>
027     * If a <tt>Time</tt> object is well defined, it will describe a peace of
028     * time (for example, with a <tt>TimeMask</tt> with YEAR, MONTH and DAY).
029     * Such a <tt>Time</tt> object is
030     * said <i>consistent for interval</i> as it can be safely converted in an
031     * <tt>Interval</tt> object.
032     *
033     * <p>
034     * A <tt>Time</tt> object does not necessary have to be <i>consistent for interval</i>.
035     * For example, it is possible to define a Time object like "9 hour and 15 minutes".
036     * This <tt>Time</tt> object is not <i>consistent for interval</i>, because it does
037     * not define a precise day, just a time in a day.
038     * But it still can be usefull, as it may be used to build other
039     * <tt>Time</tt> objects. Indeed, you can combinate it with another
040     * <tt>Time</tt> object that only defines a day,
041     * and the combinaison of both gives a <tt>Time</tt>
042     * object that defines day <i>and</i> hour/minute.
043     *
044     * <p>
045     * Please note that having a good <tt>TimeMask</tt> is not sufficient for beeing
046     * <i>consistent for interval</i>.
047     *
048     * For example, a <tt>Time</tt> object which
049     * value is [31st February of 2006] is <i>not</i> consistent for interval.
050     *
051     * <p>
052     * If a <tt>Time</tt> object provide enough information to be millisecond accurate,
053     * it is said <i>consistent for instant</i> as it can be safely converted in an
054     * <tt>Instant</tt> object. Generally, being <i>consistent for instant</i> implies
055     * to be <i>consistent for interval</i> (which one millisecond interval duration).
056     *
057     * <p>
058     * A Chronology provides the following services:
059     * <ul>
060     * <li>Methods to test <tt>Time</tt> object against <i>consistence for instant</i>
061     * and <i>consistence for interval</i>.
062     * <li>Methods to make conversion between <tt>Time</tt> and
063     * <tt>Instant</tt>/<tt>Interval</tt>
064     * <li>Methods that provided <tt>java.util.Collection</tt> views of this chronology.
065     * </ul>
066     *
067     * @author Arnaud Roques
068     *
069     * @depend - build - time.Interval
070     * @depend - build - time.Instant
071     * @depend - build - time.Time
072     * @composed - "define" n time.TimeField<V>
073     *
074     */ 
075    public interface Chronology
076    {
077            /**
078             * Return all <tt>TimeField</tt> of this chronology.
079             *
080             * <p>
081             * All <tt>TimeMask</tt> and <tt>Time</tt> object used with this chronology
082             * should only use one or several of thoses <tt>TimeField</tt> objects, 
083             * otherwise a <tt>ClassCastException</tt> will be thrown by the other
084             * methods of this chronology when such an unappropriate <tt>TimeField</tt>
085             * will be used.
086             *
087             * @return      all <tt>TimeField</tt> of this chronology
088             */
089            public SortedSet<TimeField> knownFields();
090    
091            /**
092             * Test if a <tt>Time</tt> object is <i>consistent for instant</i>.
093             *
094             * <p>
095             * A <tt>Time</tt> object is <i>consistent for instant</i>
096             * if it provides enough information to point a unique <tt>Instant</tt>
097             * in the whole Time.
098             *
099             * @param time  the <tt>Time</tt> object to be tested.
100             *
101             * @return <tt>true</tt> if <tt>time</tt> is <i>consistant for instant</i>.
102             *
103             * @throws NullPointerException if <tt>time</tt> is <tt>null</tt>
104             *
105             */
106            public boolean isConsistentForInstant(Time time);
107    
108            /**
109             * Test if a <tt>Time</tt> object is <i>consistent for interval</i>.
110             *
111             * <p>
112             * A <tt>Time</tt> object is <i>consistent for interval</i>,
113             * if it provides enough information to point a unique <tt>Interval</tt>
114             * in the whole Time (for example, a day, a week, a month...).
115             *
116             * @param time  the <tt>Time</tt> object to be tested.
117             *
118             * @return <tt>true</tt> if <tt>time</tt> is <i>consistant for interval</i>.
119             *
120             * @throws NullPointerException if <tt>time</tt> is <tt>null</tt>
121             */
122            public boolean isConsistentForInterval(Time time);
123    
124    
125            /**
126             * Convert an <tt>Instant</tt> object into a <tt>Time</tt> object
127             * with all known <tt>TimeField</tt> of this chronology.
128             *
129             * @param instant       the <tt>Instant</tt> object to be converted.
130             *
131             * @return a <tt>Time</tt> object with all known <tt>TimeField</tt> of this
132             *       chronology.
133             */
134            public Time getTime(Instant instant);
135    
136    
137            /**
138             * Convert an <tt>Instant</tt> object into a <tt>Time</tt> object
139             * with a precise <tt>TimeMask</tt> according to this chronology.
140             *
141             * <p>
142             * Calling this method should be equivalent as the following:
143             * 
144             * <br><pre>
145             *      getTime(instant).subMap(mask)
146             * </pre>
147             *
148             * @param instant       the <tt>Instant</tt> object to be converted.
149             * @param mask  the <tt>TimeMask</tt> to use.
150             *
151             * @return a <tt>Time</tt> object with <tt>mask</tt> as TimeMask.
152             *
153             * @throws ClassCastException if <tt>mask</tt> is not compatible
154             *              with this chronology.
155             *
156             * @throws NullPointerException if <tt>instant</tt> or <tt>mask</tt> is <tt>null</tt>
157             *
158             */
159            public Time getTime(Instant instant, TimeMask mask) throws ClassCastException;
160    
161            
162            /**
163             * Convert an <tt>Interval</tt> object into a <tt>Time</tt> object
164             * with all known <tt>TimeField</tt> of this chronology.
165             *
166             * @param interval      the <tt>Interval</tt> object to be converted.
167             *
168             * @return a <tt>Time</tt> object with all known <tt>TimeField</tt> of this
169             *       chronology.
170             *
171             * @throws IllegalArgumentException if <tt>interval</tt> cannot be converted into
172             *              a <tt>Time</tt> object according to this chronology.
173             *
174             * @throws NullPointerException if <tt>interval</tt> is <tt>null</tt>
175             */
176            public Time getTime(Interval interval);
177            
178            
179            
180            
181            /**
182             * Convert an <tt>Interval</tt> object into a <tt>Time</tt> object
183             * with a precise <tt>TimeMask</tt> according to this chronology.
184             *
185             * <p>
186             * Calling this method should be equivalent as the following:
187             * 
188             * <br><pre>
189             *      getTime(interval).subMap(mask)
190             * </pre>
191             *
192             * @param interval      the <tt>Interval</tt> object to be converted.
193             *
194             * @param mask  the <tt>TimeMask</tt> to use.
195             *
196             * @return a <tt>Time</tt> object with <tt>mask</tt> as TimeMask..
197             *
198             * @throws IllegalArgumentException if <tt>interval</tt> cannot be converted into
199             *              a <tt>Time</tt> object according to this chronology.
200             *
201             * @throws ClassCastException if <tt>mask</tt> is not compatible
202             *              with this chronology.
203             * @throws NullPointerException if <tt>interval</tt> or <tt>mask</tt> is <tt>null</tt>
204             * 
205             */
206            public Time getTime(Interval interval, TimeMask mask) throws ClassCastException;
207            
208            
209            
210            /**
211             * Convert a <tt>Time</tt> object into <tt>Instant</tt> according to this
212             * chronology object.
213             *
214             * @param time  the <tt>Time</tt> object to be converted.
215             *
216             * @return <tt>Instant</tt> corresponding to the <tt>t</tt> object.
217             *
218             * @throws ClassCastException if <tt>time</tt> does not have a <tt>TimeMask</tt>
219             *              compatible with this <tt>Chronology</tt> object.
220             *
221             * @throws IllegalArgumentException if <tt>time</tt> is not consistent for instant.
222             *
223             * @throws NullPointerException if <tt>time</tt> is <tt>null</tt>
224             */
225            public Instant getInstant(Time time) throws ClassCastException;
226    
227    
228    
229    
230    
231    
232            /**
233             * Convert a <tt>Time</tt> object into an <tt>Interval</tt> object,
234             * according to this chronology.
235             *
236             * @param       time    the <tt>Time</tt> object to be converted
237             *
238             * @return the <tt>Interval</tt> corresponding to <tt>t</tt>
239             *
240             * @throws ClassCastException if <tt>time</tt> is not compatible
241             *              with this chronology.
242             *
243             * @throws IllegalArgumentException if <tt>time</tt> is not consistent for
244             *  interval.
245             *
246             * @throws NullPointerException if <tt>time</tt> is <tt>null</tt>
247             */
248            public Interval getInterval(Time time) throws ClassCastException;
249            
250            
251            /**
252             * Return a immutable <i>view</i> of all <tt>Time</tt> objects of this chronology
253             * with a specified <tt>TimeMask</tt>.
254             *
255             * Such a <i>view</i> provides a bridge with <i>Java Collections Framework</i>.
256             *
257             * <p>
258             * For example, assuming that <tt>myTime</tt> is a <tt>Time</tt> object,
259             * calling:
260             * <br><pre>
261             *      asSortedSet(myTime.getTimeMask()).contains(myTime)
262             * </pre><br>
263             * returns <tt>true</tt> if <tt>myTime</tt> is <i>consistent for interval</i>.
264             *
265             * <p>
266             * Another example, assuming that <tt>dayMask</tt> is a <tt>TimeMask</tt>
267             * object like [YEAR, MONTH, DAY_OF_MONTH], and that <tt>day1</tt> and
268             * <tt>day2</tt> are two differents days,
269             * calling:
270             * <br><pre>
271             *      asSortedSet(dayMask).subSet(day1, day2).size()
272             * </pre><br>
273             * returns the number of days between <tt>day1</tt> and <tt>day2</tt> according
274             * to this chronology.
275             *
276             *
277             * <p>
278             * To have the day following <tt>day1</tt>,
279             * call:
280             * <br><pre>
281             *      Iterator<Time> it = asSortedSet(day1.getTimeMask()).tailSet(day1).iterator();
282             *      it.next(); // To skip day1
283             *      return it.next()
284             * </pre>
285             * 
286             * To have the day before <tt>day1</tt>,
287             * call:
288             * <br><pre>
289             *      asSortedSet(dayMask).headSet(day1).last()
290             * </pre>
291             *
292             * @param       mask    the specified <tt>TimeMask</tt>
293             *
294             * @return a immutable <i>view</i> of all <tt>Time</tt> objects of this chronology
295             * with a specified <tt>TimeMask</tt>.
296             *
297             * @throws NullPointerException if <tt>mask</tt> is <tt>null</tt>
298             *
299             * @throws ClassCastException if <tt>mask</tt> is not compatible with this chronology
300             *
301             * @throws IllegalArgumentException if <tt>mask</tt> is not <i>consistent with interval</i>
302             */
303            public SortedSet<Time> asSortedSet(TimeMask mask);
304            
305    
306            /**
307             * Return a immutable <i>view</i> of all <tt>Time</tt> objects of this chronology
308             * with a specified <tt>TimeMask</tt>.
309             *
310             * Such a <i>view</i> provides a bridge with <i>Java Collections Framework</i>.
311             *
312             * <p>
313             * For example, assuming that <tt>myTime</tt> is a <tt>Time</tt> object,
314             * calling:
315             * <br><pre>
316             *      asList(myTime.getTimeMask()).contains(myTime)
317             * </pre><br>
318             * returns <tt>true</tt> if <tt>myTime</tt> is <i>consistent for interval</i>.
319             *
320             * <p>
321             * To have the 100th day following <tt>day1</tt>,
322             * call:
323             * <br><pre>
324             *      int idx = asList(dayMask).indexOf(day1);
325             *      asList(dayMask).get(idx+100);
326             * </pre>
327             * <br>
328             *
329             * Please note than unlike <tt>Set</tt>, a <tt>List</tt> cannot have more
330             * than <tt>Integer.MAX_VALUE</tt>. So some <tt>mask</tt> that would have
331             * define a too big list cannot be used with this method.
332             *
333             * @param       mask    the specified <tt>TimeMask</tt>
334             *
335             * @return a immutable <i>view</i> of all <tt>Time</tt> objects of this chronology
336             * with a specified <tt>TimeMask</tt>.
337             *
338             * @throws NullPointerException if <tt>mask</tt> is <tt>null</tt>
339             *
340             * @throws ClassCastException if <tt>mask</tt> is not compatible with this chronology
341             *
342             * @throws IllegalArgumentException if <tt>mask</tt> is not <i>consistent with interval</i>
343             *
344             * @throws IndexOutOfBoundsException if the returned List would have more than
345             * <tt>Integer.MAX_VALUE</tt> elements.
346             */
347            public List<Time> asList(TimeMask mask);
348    
349    
350            /**
351             * Return a immutable <i>view</i> of some <tt>Time</tt> objects of this chronology
352             * starting at a specified <tt>Time</tt>.
353             *
354             * Such a <i>view</i> provides a bridge with <i>Java Collections Framework</i>.
355             *
356             * <p>
357             * All <tt>Time</tt> objects of the returned list have the same <tt>TimeMask</tt>
358             * as <tt>startingTime</tt>.
359             *
360             * The first element of the list is <tt>startingTime</tt> if
361             * <tt>startingPosition=0</tt>.
362             *
363             * Otherwise, if <tt>startingPosition&gt;0</tt>, it specifies the position
364             * of <tt>startingTime</tt> in the returned list.
365             *
366             * So we have:
367             * <br><pre>
368             *      asList(myTime, x).get(x).equals(myTime)==true
369             * </pre><br>
370             *
371             * If <tt>startingPosition&lt;0</tt>, the returned list does <i>not</i>
372             * contains <tt>startingTime</tt> and starts with the <tt>(-startingPosition)</tt>
373             * Time objects that follows logically <tt>startingTime</tt>.
374             *
375             * <p>To sumurize, <tt>startingPosition</tt> is always the logically (even
376             * if it's negative) position of <tt>startingTime</tt> in the returned list.
377             *
378             * <p>
379             * To have the 100th day following <tt>day1</tt>,
380             * call:
381             * <br><pre>
382             *      asList(day1, 0).get(100);
383             * </pre>or:<pre>
384             *      asList(day1, 100).get(0);
385             * </pre>
386             * <br>
387             *
388             * Please note than unlike <tt>Set</tt>, a <tt>List</tt> cannot have more
389             * than <tt>Integer.MAX_VALUE</tt>. 
390             *
391             * @param       startingTime    an absolute reference for <tt>Time</tt>
392             * @param       startingPosition        the logical position of <tt>startingTime</tt>
393             * in the returned list
394             *
395             * @return a immutable <i>view</i> of some <tt>Time</tt> objects of this chronology.
396             *
397             * @throws NullPointerException if <tt>startingTime</tt> is <tt>null</tt>
398             *
399             * @throws ClassCastException if <tt>startingTime</tt> is not compatible with this chronology
400             *
401             * @throws IllegalArgumentException if <tt>startingTime</tt> is not <i>consistent with interval</i>
402             *
403             * @throws IndexOutOfBoundsException if the returned List would have more than
404             * <tt>Integer.MAX_VALUE</tt> elements.
405             */
406            public List<Time> asList(Time startingTime, int startingPosition);
407            
408            
409            /**
410             * Return a immutable <i>view</i> with <tt>Time</tt> objects by
411             * adding some <tt>TimeField</tt> to an existing <tt>Time</tt> object.
412             *
413             * 
414             * <p>
415             * The provided <tt>timeToSplit</tt> must be <i>consistent for interval</i>.
416             * The returned set is a view of <tt>timeToSplit</tt> as set of its component.
417             * For example:
418             *
419             * <ul>
420             * <li> a year as a <i>set of its months</i>
421             * <li> a year as a <i>set of its weeks</i>
422             * <li> a month as a <i>set of days</i>
423             * <li> a day is a <i>set of hours</i>
424             * <li> ...
425             * </ul>
426             * <p>
427             * The returned set contains <tt>Time</tt> objects whose <tt>TimeMask</tt> is
428             * the time mask of <tt>timeToExplode</tt> merged with all <tt>fieldsToAdd</tt>.
429             *
430             * All possibles values are contained in the returned set.
431             *
432             * <p>
433             * For example, if one have:
434             * <br><pre>
435             *      timeToSplit = new Time(DAY_MASK, 2005, Month.NOVEMBER, 11);
436             * </pre><br>
437             *
438             * calling the following method:
439             * <br><pre>
440             *      split(timeToSplit, HOUR, MINUTE);
441             * </pre><br>
442             *
443             * return a set that contains all hours/minutes from 00:00 to 23:59.
444             * <br>
445             * [2005, NOVEMBER, 11, 0 , 0] ... [2005, NOVEMBER, 11, 0 , 59], 
446             * <br>
447             * [2005, NOVEMBER, 11, 1 , 0] ... [2005, NOVEMBER, 11, 1 , 59], 
448             * <br>
449             * [2005, NOVEMBER, 11, 2 , 0] ... [2005, NOVEMBER, 11, 2 , 59], 
450             * <br>
451             * ...
452             * <br>
453             * [2005, NOVEMBER, 11, 22 , 0] ... [2005, NOVEMBER, 11, 22 , 59], 
454             * <br>
455             * [2005, NOVEMBER, 11, 23 , 0] ... [2005, NOVEMBER, 11, 23 , 59] 
456             *
457             *
458             * <br>
459             * <br>
460             * <br>
461             * Another example, if you want to know the number of days in a month:
462             * <br><pre>
463             *      Time myMonth = new Time(MONTH_MASK, 2005, Month.DECEMBER);
464             *      int nbDays = myChronology.split(myMonth, DAY_OF_MONTH).size();
465             * </pre><br>
466             *
467             *
468             * @param       timeToSplit     the time to split.
469             * @param       fieldsToAdd             all </tt>TimeField</tt> to add.
470             *
471             * @return an immutable <i>view</i> of <tt>Time</tt> objects.
472             *
473             */
474            public SortedSet<Time> split(Time timeToSplit, TimeField... fieldsToAdd);
475            
476            /**
477             * Return the next <tt>Time</tt> object that directly follows a specified <tt>Time</tt>
478             * object according to this chronology.
479             *
480             * <p>More formally, this method returns a <tt>Time</tt> object that have the
481             * same <tt>TimeMask</tt> than <tt>time</tt>, with the following property:
482             * the ending instant (according to this chronoloy) of <tt>time</tt> is
483             * the starting instant (according to this chronology) of the resulted <tt>Time</tt>
484             * object.
485             *
486             * <p>
487             * If no exception is thrown, the following test is always <tt>true</tt>:
488             * <br><pre>
489             *      getInterval(time).getEnd().equals(next(time).getStart())
490             * </pre>
491             *
492             * <p>This is equivalent of the following call:
493             * <br><pre>
494             *      Iterator<Time> it = asSortedSet(time.getTimeMask()).tailSet(time).iterator();
495             *      it.next(); // To skip time
496             *      return it.next()
497             * </pre>
498             * 
499             *
500             * @param time the time whose next time is return
501             *
502             * @return the <tt>Time</tt> object that directly follows <tt>time</tt>.
503             *
504             * @throws ClassCastException if <tt>time</tt> does not have a <tt>TimeMask</tt>
505             *              compatible with this <tt>Chronology</tt> object.
506             *
507             * @throws IllegalArgumentException if <tt>time</tt> does not have a following
508             *              </tt>Time</tt>.
509             */
510            public Time next(Time time) throws IllegalArgumentException, ClassCastException;
511    
512            /**
513             * Return the previous <tt>Time</tt> object that is just before a specified <tt>Time</tt>
514             * object according to this chronology.
515             *
516             * <p>More formally, this method returns a <tt>Time</tt> object that have the
517             * same <tt>TimeMask</tt> than <tt>time</tt>, with the following property:
518             * the starting instant (according to this chronoloy) of <tt>time</tt> is
519             * the ending instant (according to this chronology) of the resulted <tt>Time</tt>
520             * object.
521             *
522             * <p>
523             * If no exception is thrown, the following test is always <tt>true</tt>:
524             * <br><pre>
525             *      getInterval(time).getStart().equals(previous(time).getEnd())
526             * </pre>
527             *
528             * <p>This is equivalent of the following call:
529             * <br><pre>
530             *      asSortedSet(time.getTimeMask()).headSet(time).last()
531             * </pre>
532             * 
533             *
534             * @param time the time whose previous time is return
535             *
536             * @return the <tt>Time</tt> object that is just before <tt>time</tt>.
537             *
538             * @throws ClassCastException if <tt>time</tt> does not have a <tt>TimeMask</tt>
539             *              compatible with this <tt>Chronology</tt> object.
540             *
541             * @throws IllegalArgumentException if <tt>time</tt> does not have a previous
542             *              </tt>Time</tt>.
543             */
544            public Time previous(Time time) throws IllegalArgumentException, ClassCastException;
545    
546            /*
547            public Time next(Time t, int nb) throws IllegalArgumentException, ClassCastException;
548            
549            public int diff(Time t1, Time t2) throws IllegalArgumentException, ClassCastException;
550            */
551    }
552