001: package org.obe.engine.calendar;
002:
003: import org.apache.commons.logging.Log;
004: import org.apache.commons.logging.LogFactory;
005:
006: import java.util.BitSet;
007: import java.util.Date;
008: import java.util.GregorianCalendar;
009: import java.util.TimeZone;
010:
011: public final class BusinessCalendarUtilities {
012: private static final Log _LOGGER = LogFactory
013: .getLog(BusinessCalendarUtilities.class);
014: private static final int MILLIS_IN_SECOND = 1000;
015:
016: /**
017: * Sets a range of bits in a BitSet.
018: *
019: * @param bits The BitSet to update.
020: * @param index Start index.
021: * @param count The number of bits to set.
022: */
023: public static void setBitSetBits(BitSet bits, int index, int count) {
024: if (_LOGGER.isDebugEnabled())
025: _LOGGER.debug("setBitSubset(" + bits + ')');
026:
027: for (int i = index; i < index + count; i++)
028: bits.set(i);
029: }
030:
031: /**
032: * Clears a range of bits in a BitSet.
033: *
034: * @param bits The BitSet to update.
035: * @param index Start index.
036: * @param count The number of bits to set.
037: */
038: public static void clearBitSetBits(BitSet bits, int index, int count) {
039: for (int i = index; i < index + count; i++) {
040: bits.clear(i);
041: }
042: }
043:
044: /**
045: * Computes...
046: *
047: * @param start
048: * @param end
049: * @param tz
050: * @return The number of intervals between two dates.
051: */
052: public static int getIntervalIndex(Date start, Date end, TimeZone tz) {
053: // You can't do this!!!
054: int index = (int) (((double) end.getTime() - (double) start
055: .getTime()) / (double) BusinessCalendar.INTERVAL_TIME_MILLIS);
056: int intervalsInDate = getIntervalsInDate(end, tz);
057: boolean startInDst = tz.inDaylightTime(start);
058: boolean endInDst = tz.inDaylightTime(end);
059:
060: if (_LOGGER.isDebugEnabled()) {
061: _LOGGER.debug("getIntervalIndex(" + start + ", " + end
062: + ", " + tz);
063: _LOGGER.debug("Index: " + index + ", StartInDST: "
064: + startInDst + ", EndInDST: " + endInDst + ')');
065: }
066:
067: // Have to compensate for the fact that during the DST transitions, the
068: // number of hours changes. An hour is removed in the Spring and
069: // gained in the Autumn.
070: if (intervalsInDate > BusinessCalendar.INTERVALS_PER_DAY) {
071: index += BusinessCalendar.INTERVALS_PER_HOUR;
072: } else if (intervalsInDate < BusinessCalendar.INTERVALS_PER_DAY) {
073: index -= BusinessCalendar.INTERVALS_PER_HOUR;
074: }
075:
076: return index;
077: }
078:
079: /**
080: * Computes the number of bits corresponding to a given time interval. The
081: * computation accounts for any DST changes which occur during the interval.
082: *
083: * @param start
084: * @param end
085: * @param tz
086: * @return Bit count for interval.
087: */
088: public static int countBitsForInterval(Date start, Date end,
089: TimeZone tz) {
090: return getIntervalIndex(start, end, tz);
091: }
092:
093: /**
094: * This method returns the number of intervals in a given date. This
095: * special method is required to account for the DST change date. When DST
096: * occurs, the date only has 23 hours. When DST switches to Standard, then
097: * the day has 25 hours.
098: *
099: * @param date
100: * @return The nuumber of intervals on a given day.
101: */
102: static int getIntervalsInDate(GregorianCalendar date) {
103: Date time = date.getTime();
104: TimeZone tz = date.getTimeZone();
105: return getIntervalsInDate(time, tz);
106: }
107:
108: private static int getIntervalsInDate(Date time, TimeZone tz) {
109: int intervals = BusinessCalendar.INTERVALS_PER_DAY;
110: boolean isInDST = tz.inDaylightTime(time);
111: boolean isInDSTEnd = tz.inDaylightTime(new Date(time.getTime()
112: + BusinessCalendar.MILLIS_IN_DAY - MILLIS_IN_SECOND));
113:
114: if (!isInDST && isInDSTEnd) {
115: intervals -= BusinessCalendar.INTERVALS_PER_HOUR;
116: } else if (isInDST && !isInDSTEnd) {
117: intervals += BusinessCalendar.INTERVALS_PER_HOUR;
118: }
119:
120: if (_LOGGER.isDebugEnabled()) {
121: _LOGGER.debug("Date: " + time + " isInDST: " + isInDST
122: + " isInDSTEnd: " + isInDSTEnd + " Intervals: "
123: + intervals);
124: }
125:
126: return intervals;
127: }
128:
129: static boolean isBetween(GregorianCalendar date,
130: GregorianCalendar start, GregorianCalendar end) {
131:
132: boolean between;
133: if (date.before(start))
134: between = false;
135: else
136: between = !date.after(end);
137:
138: return between;
139: }
140:
141: private BusinessCalendarUtilities() {
142: }
143: }
|