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>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<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