001: package org.quartz.impl.calendar;
002:
003: import java.text.NumberFormat;
004: import java.util.ArrayList;
005: import java.util.Calendar;
006: import java.util.StringTokenizer;
007: import java.util.TimeZone;
008:
009: /**
010: * This implementation of the Calendar excludes (or includes - see below) a
011: * specified time range each day. For example, you could use this calendar to
012: * exclude business hours (8AM - 5PM) every day. Each <CODE>DailyCalendar</CODE>
013: * only allows a single time range to be specified, and that time range may not
014: * cross daily boundaries (i.e. you cannot specify a time range from 8PM - 5AM).
015: * If the property <CODE>invertTimeRange</CODE> is <CODE>false</CODE> (default),
016: * the time range defines a range of times in which triggers are not allowed to
017: * fire. If <CODE>invertTimeRange</CODE> is <CODE>true</CODE>, the time range
018: * is inverted – that is, all times <I>outside</I> the defined time range
019: * are excluded.
020: * <P>
021: * Note when using <CODE>DailyCalendar</CODE>, it behaves on the same principals
022: * as, for example, {@link org.quartz.impl.calendar.WeeklyCalendar
023: * WeeklyCalendar}. <CODE>WeeklyCalendar</CODE> defines a set of days that are
024: * excluded <I>every week</I>. Likewise, <CODE>DailyCalendar</CODE> defines a
025: * set of times that are excluded <I>every day</I>.
026: *
027: * @author Mike Funk, Aaron Craven
028: */
029: public class DailyCalendar extends BaseCalendar {
030: static final long serialVersionUID = -7561220099904944039L;
031:
032: private static final String invalidHourOfDay = "Invalid hour of day: ";
033: private static final String invalidMinute = "Invalid minute: ";
034: private static final String invalidSecond = "Invalid second: ";
035: private static final String invalidMillis = "Invalid millis: ";
036: private static final String invalidTimeRange = "Invalid time range: ";
037: private static final String separator = " - ";
038: private static final long oneMillis = 1;
039: private static final String colon = ":";
040:
041: /** @deprecated The use of <code>name</code> is no longer supported. */
042: private String name;
043:
044: private int rangeStartingHourOfDay;
045: private int rangeStartingMinute;
046: private int rangeStartingSecond;
047: private int rangeStartingMillis;
048: private int rangeEndingHourOfDay;
049: private int rangeEndingMinute;
050: private int rangeEndingSecond;
051: private int rangeEndingMillis;
052:
053: private boolean invertTimeRange = false;
054:
055: /**
056: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
057: * specified strings and no <CODE>baseCalendar</CODE>.
058: * <CODE>rangeStartingTime</CODE> and <CODE>rangeEndingTime</CODE>
059: * must be in the format "HH:MM[:SS[:mmm]]" where:
060: * <UL><LI>HH is the hour of the specified time. The hour should be
061: * specified using military (24-hour) time and must be in the range
062: * 0 to 23.</LI>
063: * <LI>MM is the minute of the specified time and must be in the range
064: * 0 to 59.</LI>
065: * <LI>SS is the second of the specified time and must be in the range
066: * 0 to 59.</LI>
067: * <LI>mmm is the millisecond of the specified time and must be in the
068: * range 0 to 999.</LI>
069: * <LI>items enclosed in brackets ('[', ']') are optional.</LI>
070: * <LI>The time range starting time must be before the time range ending
071: * time. Note this means that a time range may not cross daily
072: * boundaries (10PM - 2AM)</LI>
073: * </UL>
074: *
075: * <p>
076: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
077: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
078: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
079: * </p>
080: *
081: * @param rangeStartingTime a String representing the starting time for the
082: * time range
083: * @param rangeEndingTime a String representing the ending time for the
084: * the time range
085: */
086: public DailyCalendar(String rangeStartingTime,
087: String rangeEndingTime) {
088: super ();
089: setTimeRange(rangeStartingTime, rangeEndingTime);
090: }
091:
092: /**
093: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
094: * specified strings and the specified <CODE>baseCalendar</CODE>.
095: * <CODE>rangeStartingTime</CODE> and <CODE>rangeEndingTime</CODE>
096: * must be in the format "HH:MM[:SS[:mmm]]" where:
097: * <UL><LI>HH is the hour of the specified time. The hour should be
098: * specified using military (24-hour) time and must be in the range
099: * 0 to 23.</LI>
100: * <LI>MM is the minute of the specified time and must be in the range
101: * 0 to 59.</LI>
102: * <LI>SS is the second of the specified time and must be in the range
103: * 0 to 59.</LI>
104: * <LI>mmm is the millisecond of the specified time and must be in the
105: * range 0 to 999.</LI>
106: * <LI>items enclosed in brackets ('[', ']') are optional.</LI>
107: * <LI>The time range starting time must be before the time range ending
108: * time. Note this means that a time range may not cross daily
109: * boundaries (10PM - 2AM)</LI>
110: * </UL>
111: *
112: * <p>
113: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
114: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
115: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
116: * </p>
117: *
118: * @param baseCalendar the base calendar for this calendar instance
119: * – see {@link BaseCalendar} for more
120: * information on base calendar functionality
121: * @param rangeStartingTime a String representing the starting time for the
122: * time range
123: * @param rangeEndingTime a String representing the ending time for the
124: * time range
125: */
126: public DailyCalendar(org.quartz.Calendar baseCalendar,
127: String rangeStartingTime, String rangeEndingTime) {
128: super (baseCalendar);
129: setTimeRange(rangeStartingTime, rangeEndingTime);
130: }
131:
132: /**
133: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
134: * specified values and no <CODE>baseCalendar</CODE>. Values are subject to
135: * the following validations:
136: * <UL><LI>Hours must be in the range 0-23 and are expressed using military
137: * (24-hour) time.</LI>
138: * <LI>Minutes must be in the range 0-59</LI>
139: * <LI>Seconds must be in the range 0-59</LI>
140: * <LI>Milliseconds must be in the range 0-999</LI>
141: * <LI>The time range starting time must be before the time range ending
142: * time. Note this means that a time range may not cross daily
143: * boundaries (10PM - 2AM)</LI>
144: * </UL>
145: *
146: * <p>
147: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
148: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
149: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
150: * </p>
151: *
152: * @param rangeStartingHourOfDay the hour of the start of the time range
153: * @param rangeStartingMinute the minute of the start of the time range
154: * @param rangeStartingSecond the second of the start of the time range
155: * @param rangeStartingMillis the millisecond of the start of the time
156: * range
157: * @param rangeEndingHourOfDay the hour of the end of the time range
158: * @param rangeEndingMinute the minute of the end of the time range
159: * @param rangeEndingSecond the second of the end of the time range
160: * @param rangeEndingMillis the millisecond of the start of the time
161: * range
162: */
163: public DailyCalendar(int rangeStartingHourOfDay,
164: int rangeStartingMinute, int rangeStartingSecond,
165: int rangeStartingMillis, int rangeEndingHourOfDay,
166: int rangeEndingMinute, int rangeEndingSecond,
167: int rangeEndingMillis) {
168: super ();
169: setTimeRange(rangeStartingHourOfDay, rangeStartingMinute,
170: rangeStartingSecond, rangeStartingMillis,
171: rangeEndingHourOfDay, rangeEndingMinute,
172: rangeEndingSecond, rangeEndingMillis);
173: }
174:
175: /**
176: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
177: * specified values and the specified <CODE>baseCalendar</CODE>. Values are
178: * subject to the following validations:
179: * <UL><LI>Hours must be in the range 0-23 and are expressed using military
180: * (24-hour) time.</LI>
181: * <LI>Minutes must be in the range 0-59</LI>
182: * <LI>Seconds must be in the range 0-59</LI>
183: * <LI>Milliseconds must be in the range 0-999</LI>
184: * <LI>The time range starting time must be before the time range ending
185: * time. Note this means that a time range may not cross daily
186: * boundaries (10PM - 2AM)</LI>
187: * </UL>
188: *
189: * <p>
190: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
191: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
192: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
193: * </p>
194: *
195: * @param baseCalendar the base calendar for this calendar
196: * instance – see
197: * {@link BaseCalendar} for more
198: * information on base calendar
199: * functionality
200: * @param rangeStartingHourOfDay the hour of the start of the time range
201: * @param rangeStartingMinute the minute of the start of the time range
202: * @param rangeStartingSecond the second of the start of the time range
203: * @param rangeStartingMillis the millisecond of the start of the time
204: * range
205: * @param rangeEndingHourOfDay the hour of the end of the time range
206: * @param rangeEndingMinute the minute of the end of the time range
207: * @param rangeEndingSecond the second of the end of the time range
208: * @param rangeEndingMillis the millisecond of the start of the time
209: * range
210: */
211: public DailyCalendar(org.quartz.Calendar baseCalendar,
212: int rangeStartingHourOfDay, int rangeStartingMinute,
213: int rangeStartingSecond, int rangeStartingMillis,
214: int rangeEndingHourOfDay, int rangeEndingMinute,
215: int rangeEndingSecond, int rangeEndingMillis) {
216: super (baseCalendar);
217: setTimeRange(rangeStartingHourOfDay, rangeStartingMinute,
218: rangeStartingSecond, rangeStartingMillis,
219: rangeEndingHourOfDay, rangeEndingMinute,
220: rangeEndingSecond, rangeEndingMillis);
221: }
222:
223: /**
224: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
225: * specified <CODE>java.util.Calendar</CODE>s and no
226: * <CODE>baseCalendar</CODE>. The Calendars are subject to the following
227: * considerations:
228: * <UL><LI>Only the time-of-day fields of the specified Calendars will be
229: * used (the date fields will be ignored)</LI>
230: * <LI>The starting time must be before the ending time of the defined
231: * time range. Note this means that a time range may not cross
232: * daily boundaries (10PM - 2AM). <I>(because only time fields are
233: * are used, it is possible for two Calendars to represent a valid
234: * time range and
235: * <CODE>rangeStartingCalendar.after(rangeEndingCalendar) ==
236: * true</CODE>)</I></LI>
237: * </UL>
238: *
239: * <p>
240: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
241: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
242: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
243: * </p>
244: *
245: * @param rangeStartingCalendar a java.util.Calendar representing the
246: * starting time for the time range
247: * @param rangeEndingCalendar a java.util.Calendar representing the ending
248: * time for the time range
249: */
250: public DailyCalendar(Calendar rangeStartingCalendar,
251: Calendar rangeEndingCalendar) {
252: super ();
253: setTimeRange(rangeStartingCalendar, rangeEndingCalendar);
254: }
255:
256: /**
257: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
258: * specified <CODE>java.util.Calendar</CODE>s and the specified
259: * <CODE>baseCalendar</CODE>. The Calendars are subject to the following
260: * considerations:
261: * <UL><LI>Only the time-of-day fields of the specified Calendars will be
262: * used (the date fields will be ignored)</LI>
263: * <LI>The starting time must be before the ending time of the defined
264: * time range. Note this means that a time range may not cross
265: * daily boundaries (10PM - 2AM). <I>(because only time fields are
266: * are used, it is possible for two Calendars to represent a valid
267: * time range and
268: * <CODE>rangeStartingCalendar.after(rangeEndingCalendar) ==
269: * true</CODE>)</I></LI>
270: * </UL>
271: *
272: * <p>
273: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
274: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
275: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>
276: * </p>
277: *
278: * @param baseCalendar the base calendar for this calendar instance
279: * – see {@link BaseCalendar} for more
280: * information on base calendar functionality
281: * @param rangeStartingCalendar a java.util.Calendar representing the
282: * starting time for the time range
283: * @param rangeEndingCalendar a java.util.Calendar representing the ending
284: * time for the time range
285: */
286: public DailyCalendar(org.quartz.Calendar baseCalendar,
287: Calendar rangeStartingCalendar, Calendar rangeEndingCalendar) {
288: super (baseCalendar);
289: setTimeRange(rangeStartingCalendar, rangeEndingCalendar);
290: }
291:
292: /**
293: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
294: * specified values and no <CODE>baseCalendar</CODE>. The values are
295: * subject to the following considerations:
296: * <UL><LI>Only the time-of-day portion of the specified values will be
297: * used</LI>
298: * <LI>The starting time must be before the ending time of the defined
299: * time range. Note this means that a time range may not cross
300: * daily boundaries (10PM - 2AM). <I>(because only time value are
301: * are used, it is possible for the two values to represent a valid
302: * time range and <CODE>rangeStartingTime >
303: * rangeEndingTime</CODE>)</I></LI>
304: * </UL>
305: *
306: * <p>
307: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
308: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
309: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>.
310: * You should use <code>{@link #DailyCalendar(String, TimeZone, long, long)}</code>
311: * if you don't want the given <code>rangeStartingTimeInMillis</code> and
312: * <code>rangeEndingTimeInMillis</code> to be evaluated in the default
313: * time zone.
314: * </p>
315: *
316: * @param rangeStartingTimeInMillis a long representing the starting time
317: * for the time range
318: * @param rangeEndingTimeInMillis a long representing the ending time for
319: * the time range
320: */
321: public DailyCalendar(long rangeStartingTimeInMillis,
322: long rangeEndingTimeInMillis) {
323: super ();
324: setTimeRange(rangeStartingTimeInMillis, rangeEndingTimeInMillis);
325: }
326:
327: /**
328: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
329: * specified values and the specified <CODE>baseCalendar</CODE>. The values
330: * are subject to the following considerations:
331: * <UL><LI>Only the time-of-day portion of the specified values will be
332: * used</LI>
333: * <LI>The starting time must be before the ending time of the defined
334: * time range. Note this means that a time range may not cross
335: * daily boundaries (10PM - 2AM). <I>(because only time value are
336: * are used, it is possible for the two values to represent a valid
337: * time range and <CODE>rangeStartingTime >
338: * rangeEndingTime</CODE>)</I></LI>
339: * </UL>
340: *
341: * <p>
342: * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the
343: * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit
344: * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>.
345: * You should use <code>{@link #DailyCalendar(String, Calendar, TimeZone, long, long)}</code>
346: * if you don't want the given <code>rangeStartingTimeInMillis</code> and
347: * <code>rangeEndingTimeInMillis</code> to be evaluated in the default
348: * time zone.
349: * </p>
350: *
351: * @param baseCalendar the base calendar for this calendar
352: * instance – see {@link
353: * BaseCalendar} for more information on
354: * base calendar functionality
355: * @param rangeStartingTimeInMillis a long representing the starting time
356: * for the time range
357: * @param rangeEndingTimeInMillis a long representing the ending time for
358: * the time range
359: */
360: public DailyCalendar(org.quartz.Calendar baseCalendar,
361: long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) {
362: super (baseCalendar);
363: setTimeRange(rangeStartingTimeInMillis, rangeEndingTimeInMillis);
364: }
365:
366: /**
367: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
368: * specified values and no <CODE>baseCalendar</CODE>. The values are
369: * subject to the following considerations:
370: * <UL><LI>Only the time-of-day portion of the specified values will be
371: * used</LI>
372: * <LI>The starting time must be before the ending time of the defined
373: * time range. Note this means that a time range may not cross
374: * daily boundaries (10PM - 2AM). <I>(because only time value are
375: * are used, it is possible for the two values to represent a valid
376: * time range and <CODE>rangeStartingTime >
377: * rangeEndingTime</CODE>)</I></LI>
378: * </UL>
379: *
380: * @param timeZone the time zone for of the
381: * <code>DailyCalendar</code> which will
382: * also be used to resolve the given
383: * start/end times.
384: * @param rangeStartingTimeInMillis a long representing the starting time
385: * for the time range
386: * @param rangeEndingTimeInMillis a long representing the ending time for
387: * the time range
388: */
389: public DailyCalendar(TimeZone timeZone,
390: long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) {
391: super (timeZone);
392: setTimeRange(rangeStartingTimeInMillis, rangeEndingTimeInMillis);
393: }
394:
395: /**
396: * Create a <CODE>DailyCalendar</CODE> with a time range defined by the
397: * specified values and the specified <CODE>baseCalendar</CODE>. The values
398: * are subject to the following considerations:
399: * <UL><LI>Only the time-of-day portion of the specified values will be
400: * used</LI>
401: * <LI>The starting time must be before the ending time of the defined
402: * time range. Note this means that a time range may not cross
403: * daily boundaries (10PM - 2AM). <I>(because only time value are
404: * are used, it is possible for the two values to represent a valid
405: * time range and <CODE>rangeStartingTime >
406: * rangeEndingTime</CODE>)</I></LI>
407: * </UL>
408: *
409: * @param baseCalendar the base calendar for this calendar
410: * instance – see {@link
411: * BaseCalendar} for more information on
412: * base calendar functionality
413: * @param timeZone the time zone for of the
414: * <code>DailyCalendar</code> which will
415: * also be used to resolve the given
416: * start/end times.
417: * @param rangeStartingTimeInMillis a long representing the starting time
418: * for the time range
419: * @param rangeEndingTimeInMillis a long representing the ending time for
420: * the time range
421: */
422: public DailyCalendar(org.quartz.Calendar baseCalendar,
423: TimeZone timeZone, long rangeStartingTimeInMillis,
424: long rangeEndingTimeInMillis) {
425: super (baseCalendar, timeZone);
426: setTimeRange(rangeStartingTimeInMillis, rangeEndingTimeInMillis);
427: }
428:
429: /**
430: * @deprecated The use of <code>name</code> is no longer supported.
431: *
432: * @see DailyCalendar#DailyCalendar(String, String)
433: */
434: public DailyCalendar(String name, String rangeStartingTime,
435: String rangeEndingTime) {
436: this (rangeStartingTime, rangeEndingTime);
437: this .name = name;
438: }
439:
440: /**
441: * @deprecated The use of <code>name</code> is no longer supported.
442: *
443: * @see DailyCalendar#DailyCalendar(org.quartz.Calendar, String, String)
444: */
445: public DailyCalendar(String name, org.quartz.Calendar baseCalendar,
446: String rangeStartingTime, String rangeEndingTime) {
447: this (baseCalendar, rangeStartingTime, rangeEndingTime);
448: this .name = name;
449: }
450:
451: /**
452: * @deprecated The use of <code>name</code> is no longer supported.
453: *
454: * @see DailyCalendar#DailyCalendar(int, int, int, int, int, int, int, int)
455: */
456: public DailyCalendar(String name, int rangeStartingHourOfDay,
457: int rangeStartingMinute, int rangeStartingSecond,
458: int rangeStartingMillis, int rangeEndingHourOfDay,
459: int rangeEndingMinute, int rangeEndingSecond,
460: int rangeEndingMillis) {
461: this (rangeStartingHourOfDay, rangeStartingMinute,
462: rangeStartingSecond, rangeStartingMillis,
463: rangeEndingHourOfDay, rangeEndingMinute,
464: rangeEndingSecond, rangeEndingMillis);
465: this .name = name;
466: }
467:
468: /**
469: * @deprecated The use of <code>name</code> is no longer supported.
470: *
471: * @see DailyCalendar#DailyCalendar(org.quartz.Calendar, int, int, int, int, int, int, int, int)
472: */
473: public DailyCalendar(String name, org.quartz.Calendar baseCalendar,
474: int rangeStartingHourOfDay, int rangeStartingMinute,
475: int rangeStartingSecond, int rangeStartingMillis,
476: int rangeEndingHourOfDay, int rangeEndingMinute,
477: int rangeEndingSecond, int rangeEndingMillis) {
478: this (baseCalendar, rangeStartingHourOfDay, rangeStartingMinute,
479: rangeStartingSecond, rangeStartingMillis,
480: rangeEndingHourOfDay, rangeEndingMinute,
481: rangeEndingSecond, rangeEndingMillis);
482: this .name = name;
483: }
484:
485: /**
486: * @deprecated The use of <code>name</code> is no longer supported.
487: *
488: * @see DailyCalendar#DailyCalendar(Calendar, Calendar)
489: */
490: public DailyCalendar(String name, Calendar rangeStartingCalendar,
491: Calendar rangeEndingCalendar) {
492: this (rangeStartingCalendar, rangeEndingCalendar);
493: this .name = name;
494: }
495:
496: /**
497: * @deprecated The use of <code>name</code> is no longer supported.
498: *
499: * @see DailyCalendar#DailyCalendar(org.quartz.Calendar, Calendar, Calendar)
500: */
501: public DailyCalendar(String name, org.quartz.Calendar baseCalendar,
502: Calendar rangeStartingCalendar, Calendar rangeEndingCalendar) {
503: this (baseCalendar, rangeStartingCalendar, rangeEndingCalendar);
504: this .name = name;
505: }
506:
507: /**
508: * @deprecated The use of <code>name</code> is no longer supported.
509: *
510: * @see DailyCalendar#DailyCalendar(long, long)
511: */
512: public DailyCalendar(String name, long rangeStartingTimeInMillis,
513: long rangeEndingTimeInMillis) {
514: this (rangeStartingTimeInMillis, rangeEndingTimeInMillis);
515: this .name = name;
516: }
517:
518: /**
519: * @deprecated The use of <code>name</code> is no longer supported.
520: *
521: * @see DailyCalendar#DailyCalendar(org.quartz.Calendar, long, long)
522: */
523: public DailyCalendar(String name, org.quartz.Calendar baseCalendar,
524: long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) {
525: this (baseCalendar, rangeStartingTimeInMillis,
526: rangeEndingTimeInMillis);
527: this .name = name;
528: }
529:
530: /**
531: * @deprecated The use of <code>name</code> is no longer supported.
532: *
533: * @see DailyCalendar#DailyCalendar(TimeZone, long, long)
534: */
535: public DailyCalendar(String name, TimeZone timeZone,
536: long rangeStartingTimeInMillis, long rangeEndingTimeInMillis) {
537: this (timeZone, rangeStartingTimeInMillis,
538: rangeEndingTimeInMillis);
539: this .name = name;
540: }
541:
542: /**
543: * @deprecated The use of <code>name</code> is no longer supported.
544: *
545: * @see DailyCalendar#DailyCalendar(org.quartz.Calendar, TimeZone, long, long)
546: */
547: public DailyCalendar(String name, org.quartz.Calendar baseCalendar,
548: TimeZone timeZone, long rangeStartingTimeInMillis,
549: long rangeEndingTimeInMillis) {
550: this (baseCalendar, timeZone, rangeStartingTimeInMillis,
551: rangeEndingTimeInMillis);
552: this .name = name;
553: }
554:
555: /**
556: * Returns the name of the <CODE>DailyCalendar</CODE>
557: *
558: * @return the name of the <CODE>DailyCalendar</CODE>
559: *
560: * @deprecated The use of <code>name</code> is no longer supported.
561: */
562: public String getName() {
563: return name;
564: }
565:
566: /**
567: * Determines whether the given time (in milliseconds) is 'included' by the
568: * <CODE>BaseCalendar</CODE>
569: *
570: * @param timeInMillis the date/time to test
571: * @return a boolean indicating whether the specified time is 'included' by
572: * the <CODE>BaseCalendar</CODE>
573: */
574: public boolean isTimeIncluded(long timeInMillis) {
575: if ((getBaseCalendar() != null)
576: && (getBaseCalendar().isTimeIncluded(timeInMillis) == false)) {
577: return false;
578: }
579:
580: long startOfDayInMillis = getStartOfDayJavaCalendar(
581: timeInMillis).getTime().getTime();
582: long endOfDayInMillis = getEndOfDayJavaCalendar(timeInMillis)
583: .getTime().getTime();
584: long timeRangeStartingTimeInMillis = getTimeRangeStartingTimeInMillis(timeInMillis);
585: long timeRangeEndingTimeInMillis = getTimeRangeEndingTimeInMillis(timeInMillis);
586: if (!invertTimeRange) {
587: return ((timeInMillis > startOfDayInMillis && timeInMillis < timeRangeStartingTimeInMillis) || (timeInMillis > timeRangeEndingTimeInMillis && timeInMillis < endOfDayInMillis));
588: } else {
589: return ((timeInMillis >= timeRangeStartingTimeInMillis) && (timeInMillis <= timeRangeEndingTimeInMillis));
590: }
591: }
592:
593: /**
594: * Determines the next time included by the <CODE>DailyCalendar</CODE>
595: * after the specified time.
596: *
597: * @param timeInMillis the initial date/time after which to find an
598: * included time
599: * @return the time in milliseconds representing the next time included
600: * after the specified time.
601: */
602: public long getNextIncludedTime(long timeInMillis) {
603: long nextIncludedTime = timeInMillis + oneMillis;
604:
605: while (!isTimeIncluded(nextIncludedTime)) {
606: if (!invertTimeRange) {
607: //If the time is in a range excluded by this calendar, we can
608: // move to the end of the excluded time range and continue
609: // testing from there. Otherwise, if nextIncludedTime is
610: // excluded by the baseCalendar, ask it the next time it
611: // includes and begin testing from there. Failing this, add one
612: // millisecond and continue testing.
613: if ((nextIncludedTime >= getTimeRangeStartingTimeInMillis(nextIncludedTime))
614: && (nextIncludedTime <= getTimeRangeEndingTimeInMillis(nextIncludedTime))) {
615:
616: nextIncludedTime = getTimeRangeEndingTimeInMillis(nextIncludedTime)
617: + oneMillis;
618: } else if ((getBaseCalendar() != null)
619: && (!getBaseCalendar().isTimeIncluded(
620: nextIncludedTime))) {
621: nextIncludedTime = getBaseCalendar()
622: .getNextIncludedTime(nextIncludedTime);
623: } else {
624: nextIncludedTime++;
625: }
626: } else {
627: //If the time is in a range excluded by this calendar, we can
628: // move to the end of the excluded time range and continue
629: // testing from there. Otherwise, if nextIncludedTime is
630: // excluded by the baseCalendar, ask it the next time it
631: // includes and begin testing from there. Failing this, add one
632: // millisecond and continue testing.
633: if (nextIncludedTime < getTimeRangeStartingTimeInMillis(nextIncludedTime)) {
634: nextIncludedTime = getTimeRangeStartingTimeInMillis(nextIncludedTime);
635: } else if (nextIncludedTime > getTimeRangeEndingTimeInMillis(nextIncludedTime)) {
636: //(move to start of next day)
637: nextIncludedTime = getEndOfDayJavaCalendar(
638: nextIncludedTime).getTime().getTime();
639: nextIncludedTime += 1l;
640: } else if ((getBaseCalendar() != null)
641: && (!getBaseCalendar().isTimeIncluded(
642: nextIncludedTime))) {
643: nextIncludedTime = getBaseCalendar()
644: .getNextIncludedTime(nextIncludedTime);
645: } else {
646: nextIncludedTime++;
647: }
648: }
649: }
650:
651: return nextIncludedTime;
652: }
653:
654: /**
655: * Returns the start time of the time range (in milliseconds) of the day
656: * specified in <CODE>timeInMillis</CODE>
657: *
658: * @param timeInMillis a time containing the desired date for the starting
659: * time of the time range.
660: * @return a date/time (in milliseconds) representing the start time of the
661: * time range for the specified date.
662: */
663: public long getTimeRangeStartingTimeInMillis(long timeInMillis) {
664: Calendar rangeStartingTime = createJavaCalendar(timeInMillis);
665: rangeStartingTime.set(Calendar.HOUR_OF_DAY,
666: rangeStartingHourOfDay);
667: rangeStartingTime.set(Calendar.MINUTE, rangeStartingMinute);
668: rangeStartingTime.set(Calendar.SECOND, rangeStartingSecond);
669: rangeStartingTime
670: .set(Calendar.MILLISECOND, rangeStartingMillis);
671: return rangeStartingTime.getTime().getTime();
672: }
673:
674: /**
675: * Returns the end time of the time range (in milliseconds) of the day
676: * specified in <CODE>timeInMillis</CODE>
677: *
678: * @param timeInMillis a time containing the desired date for the ending
679: * time of the time range.
680: * @return a date/time (in milliseconds) representing the end time of the
681: * time range for the specified date.
682: */
683: public long getTimeRangeEndingTimeInMillis(long timeInMillis) {
684: Calendar rangeEndingTime = createJavaCalendar(timeInMillis);
685: rangeEndingTime.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay);
686: rangeEndingTime.set(Calendar.MINUTE, rangeEndingMinute);
687: rangeEndingTime.set(Calendar.SECOND, rangeEndingSecond);
688: rangeEndingTime.set(Calendar.MILLISECOND, rangeEndingMillis);
689: return rangeEndingTime.getTime().getTime();
690: }
691:
692: /**
693: * Indicates whether the time range represents an inverted time range (see
694: * class description).
695: *
696: * @return a boolean indicating whether the time range is inverted
697: */
698: public boolean getInvertTimeRange() {
699: return invertTimeRange;
700: }
701:
702: /**
703: * Indicates whether the time range represents an inverted time range (see
704: * class description).
705: *
706: * @param flag the new value for the <CODE>invertTimeRange</CODE> flag.
707: */
708: public void setInvertTimeRange(boolean flag) {
709: this .invertTimeRange = flag;
710: }
711:
712: /**
713: * Returns a string representing the properties of the
714: * <CODE>DailyCalendar</CODE>
715: *
716: * @return the properteis of the DailyCalendar in a String format
717: */
718: public String toString() {
719: NumberFormat numberFormatter = NumberFormat.getNumberInstance();
720: numberFormatter.setMaximumFractionDigits(0);
721: numberFormatter.setMinimumIntegerDigits(2);
722: StringBuffer buffer = new StringBuffer();
723: if (name != null) {
724: buffer.append(name).append(": ");
725: }
726: buffer.append("base calendar: [");
727: if (getBaseCalendar() != null) {
728: buffer.append(getBaseCalendar().toString());
729: } else {
730: buffer.append("null");
731: }
732: buffer.append("], time range: '");
733: buffer.append(numberFormatter.format(rangeStartingHourOfDay));
734: buffer.append(":");
735: buffer.append(numberFormatter.format(rangeStartingMinute));
736: buffer.append(":");
737: buffer.append(numberFormatter.format(rangeStartingSecond));
738: buffer.append(":");
739: numberFormatter.setMinimumIntegerDigits(3);
740: buffer.append(numberFormatter.format(rangeStartingMillis));
741: numberFormatter.setMinimumIntegerDigits(2);
742: buffer.append(" - ");
743: buffer.append(numberFormatter.format(rangeEndingHourOfDay));
744: buffer.append(":");
745: buffer.append(numberFormatter.format(rangeEndingMinute));
746: buffer.append(":");
747: buffer.append(numberFormatter.format(rangeEndingSecond));
748: buffer.append(":");
749: numberFormatter.setMinimumIntegerDigits(3);
750: buffer.append(numberFormatter.format(rangeEndingMillis));
751: buffer.append("', inverted: " + invertTimeRange + "]");
752: return buffer.toString();
753: }
754:
755: /**
756: * Helper method to split the given string by the given delimiter.
757: */
758: private String[] split(String string, String delim) {
759: ArrayList result = new ArrayList();
760:
761: StringTokenizer stringTokenizer = new StringTokenizer(string,
762: delim);
763: while (stringTokenizer.hasMoreTokens()) {
764: result.add(stringTokenizer.nextToken());
765: }
766:
767: return (String[]) result.toArray(new String[result.size()]);
768: }
769:
770: /**
771: * Sets the time range for the <CODE>DailyCalendar</CODE> to the times
772: * represented in the specified Strings.
773: *
774: * @param rangeStartingTimeString a String representing the start time of
775: * the time range
776: * @param rangeEndingTimeString a String representing the end time of the
777: * excluded time range
778: */
779: private void setTimeRange(String rangeStartingTimeString,
780: String rangeEndingTimeString) {
781: String[] rangeStartingTime;
782: int rangeStartingHourOfDay;
783: int rangeStartingMinute;
784: int rangeStartingSecond;
785: int rangeStartingMillis;
786:
787: String[] rangeEndingTime;
788: int rangeEndingHourOfDay;
789: int rangeEndingMinute;
790: int rangeEndingSecond;
791: int rangeEndingMillis;
792:
793: rangeStartingTime = split(rangeStartingTimeString, colon);
794:
795: if ((rangeStartingTime.length < 2)
796: || (rangeStartingTime.length > 4)) {
797: throw new IllegalArgumentException("Invalid time string '"
798: + rangeStartingTimeString + "'");
799: }
800:
801: rangeStartingHourOfDay = Integer.parseInt(rangeStartingTime[0]);
802: rangeStartingMinute = Integer.parseInt(rangeStartingTime[1]);
803: if (rangeStartingTime.length > 2) {
804: rangeStartingSecond = Integer
805: .parseInt(rangeStartingTime[2]);
806: } else {
807: rangeStartingSecond = 0;
808: }
809: if (rangeStartingTime.length == 4) {
810: rangeStartingMillis = Integer
811: .parseInt(rangeStartingTime[3]);
812: } else {
813: rangeStartingMillis = 0;
814: }
815:
816: rangeEndingTime = split(rangeEndingTimeString, colon);
817:
818: if ((rangeEndingTime.length < 2)
819: || (rangeEndingTime.length > 4)) {
820: throw new IllegalArgumentException("Invalid time string '"
821: + rangeEndingTimeString + "'");
822: }
823:
824: rangeEndingHourOfDay = Integer.parseInt(rangeEndingTime[0]);
825: rangeEndingMinute = Integer.parseInt(rangeEndingTime[1]);
826: if (rangeEndingTime.length > 2) {
827: rangeEndingSecond = Integer.parseInt(rangeEndingTime[2]);
828: } else {
829: rangeEndingSecond = 0;
830: }
831: if (rangeEndingTime.length == 4) {
832: rangeEndingMillis = Integer.parseInt(rangeEndingTime[3]);
833: } else {
834: rangeEndingMillis = 0;
835: }
836:
837: setTimeRange(rangeStartingHourOfDay, rangeStartingMinute,
838: rangeStartingSecond, rangeStartingMillis,
839: rangeEndingHourOfDay, rangeEndingMinute,
840: rangeEndingSecond, rangeEndingMillis);
841: }
842:
843: /**
844: * Sets the time range for the <CODE>DailyCalendar</CODE> to the times
845: * represented in the specified values.
846: *
847: * @param rangeStartingHourOfDay the hour of the start of the time range
848: * @param rangeStartingMinute the minute of the start of the time range
849: * @param rangeStartingSecond the second of the start of the time range
850: * @param rangeStartingMillis the millisecond of the start of the time
851: * range
852: * @param rangeEndingHourOfDay the hour of the end of the time range
853: * @param rangeEndingMinute the minute of the end of the time range
854: * @param rangeEndingSecond the second of the end of the time range
855: * @param rangeEndingMillis the millisecond of the start of the time
856: * range
857: */
858: private void setTimeRange(int rangeStartingHourOfDay,
859: int rangeStartingMinute, int rangeStartingSecond,
860: int rangeStartingMillis, int rangeEndingHourOfDay,
861: int rangeEndingMinute, int rangeEndingSecond,
862: int rangeEndingMillis) {
863: validate(rangeStartingHourOfDay, rangeStartingMinute,
864: rangeStartingSecond, rangeStartingMillis);
865:
866: validate(rangeEndingHourOfDay, rangeEndingMinute,
867: rangeEndingSecond, rangeEndingMillis);
868:
869: Calendar startCal = createJavaCalendar();
870: startCal.set(Calendar.HOUR_OF_DAY, rangeStartingHourOfDay);
871: startCal.set(Calendar.MINUTE, rangeStartingMinute);
872: startCal.set(Calendar.SECOND, rangeStartingSecond);
873: startCal.set(Calendar.MILLISECOND, rangeStartingMillis);
874:
875: Calendar endCal = createJavaCalendar();
876: endCal.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay);
877: endCal.set(Calendar.MINUTE, rangeEndingMinute);
878: endCal.set(Calendar.SECOND, rangeEndingSecond);
879: endCal.set(Calendar.MILLISECOND, rangeEndingMillis);
880:
881: if (!startCal.before(endCal)) {
882: throw new IllegalArgumentException(invalidTimeRange
883: + rangeStartingHourOfDay + ":"
884: + rangeStartingMinute + ":" + rangeStartingSecond
885: + ":" + rangeStartingMillis + separator
886: + rangeEndingHourOfDay + ":" + rangeEndingMinute
887: + ":" + rangeEndingSecond + ":" + rangeEndingMillis);
888: }
889:
890: this .rangeStartingHourOfDay = rangeStartingHourOfDay;
891: this .rangeStartingMinute = rangeStartingMinute;
892: this .rangeStartingSecond = rangeStartingSecond;
893: this .rangeStartingMillis = rangeStartingMillis;
894: this .rangeEndingHourOfDay = rangeEndingHourOfDay;
895: this .rangeEndingMinute = rangeEndingMinute;
896: this .rangeEndingSecond = rangeEndingSecond;
897: this .rangeEndingMillis = rangeEndingMillis;
898: }
899:
900: /**
901: * Sets the time range for the <CODE>DailyCalendar</CODE> to the times
902: * represented in the specified <CODE>java.util.Calendar</CODE>s.
903: *
904: * @param rangeStartingCalendar a Calendar containing the start time for
905: * the <CODE>DailyCalendar</CODE>
906: * @param rangeEndingCalendar a Calendar containing the end time for
907: * the <CODE>DailyCalendar</CODE>
908: */
909: private void setTimeRange(Calendar rangeStartingCalendar,
910: Calendar rangeEndingCalendar) {
911: setTimeRange(rangeStartingCalendar.get(Calendar.HOUR_OF_DAY),
912: rangeStartingCalendar.get(Calendar.MINUTE),
913: rangeStartingCalendar.get(Calendar.SECOND),
914: rangeStartingCalendar.get(Calendar.MILLISECOND),
915: rangeEndingCalendar.get(Calendar.HOUR_OF_DAY),
916: rangeEndingCalendar.get(Calendar.MINUTE),
917: rangeEndingCalendar.get(Calendar.SECOND),
918: rangeEndingCalendar.get(Calendar.MILLISECOND));
919: }
920:
921: /**
922: * Sets the time range for the <CODE>DailyCalendar</CODE> to the times
923: * represented in the specified values.
924: *
925: * @param rangeStartingTime the starting time (in milliseconds) for the
926: * time range
927: * @param rangeEndingTime the ending time (in milliseconds) for the time
928: * range
929: */
930: private void setTimeRange(long rangeStartingTime,
931: long rangeEndingTime) {
932: setTimeRange(createJavaCalendar(rangeStartingTime),
933: createJavaCalendar(rangeEndingTime));
934: }
935:
936: /**
937: * Checks the specified values for validity as a set of time values.
938: *
939: * @param hourOfDay the hour of the time to check (in military (24-hour)
940: * time)
941: * @param minute the minute of the time to check
942: * @param second the second of the time to check
943: * @param millis the millisecond of the time to check
944: */
945: private void validate(int hourOfDay, int minute, int second,
946: int millis) {
947: if (hourOfDay < 0 || hourOfDay > 23) {
948: throw new IllegalArgumentException(invalidHourOfDay
949: + hourOfDay);
950: }
951: if (minute < 0 || minute > 59) {
952: throw new IllegalArgumentException(invalidMinute + minute);
953: }
954: if (second < 0 || second > 59) {
955: throw new IllegalArgumentException(invalidSecond + second);
956: }
957: if (millis < 0 || millis > 999) {
958: throw new IllegalArgumentException(invalidMillis + millis);
959: }
960: }
961: }
|