svn commit: r903125 [2/2] - in /ofbiz/branches/release09.04: ./ applications/workeffort/src/org/ofbiz/workeffort/workeffort/ framework/common/config/ framework/common/servicedef/ framework/common/webcommon/includes/ framework/service/data/ framework/se...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r903125 [2/2] - in /ofbiz/branches/release09.04: ./ applications/workeffort/src/org/ofbiz/workeffort/workeffort/ framework/common/config/ framework/common/servicedef/ framework/common/webcommon/includes/ framework/service/data/ framework/se...

adrianc
Modified: ofbiz/branches/release09.04/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release09.04/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java?rev=903125&r1=903124&r2=903125&view=diff
==============================================================================
--- ofbiz/branches/release09.04/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java (original)
+++ ofbiz/branches/release09.04/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java Tue Jan 26 08:28:39 2010
@@ -24,7 +24,9 @@
 import java.util.Date;
 import java.util.Set;
 import java.util.TreeSet;
+
 import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilValidate;
 
 /** A collection of TemporalExpression classes.
  * <p>For the most part, these classes are immutable - with the exception
@@ -35,259 +37,418 @@
 public class TemporalExpressions implements Serializable {
     public static final String module = TemporalExpressions.class.getName();
     public static final TemporalExpression NullExpression = new Null();
+    // Expressions are evaluated from smallest unit of time to largest.
+    // When unit of time is the same, then they are evaluated from
+    // least ambiguous to most. Frequency should always be first -
+    // since it is the most specific. Date range should always be last.
+    // The idea is to evaluate all other expressions, then check to see
+    // if the result falls within the date range.
+    // Difference: adopts the sequence of its include expression
+    // Intersection: aggregates member expression sequence values
+    // Union: adopts the sequence of its first member expression
+    public static final int SEQUENCE_DATE_RANGE = 800;
+    public static final int SEQUENCE_DAY_IN_MONTH = 460;
+    public static final int SEQUENCE_DOM_RANGE = 400;
+    public static final int SEQUENCE_DOW_RANGE = 450;
+    public static final int SEQUENCE_FREQ = 100;
+    public static final int SEQUENCE_HOUR_RANGE = 300;
+    public static final int SEQUENCE_MINUTE_RANGE = 200;
+    public static final int SEQUENCE_MONTH_RANGE = 600;
+    public static final int SEQUENCE_TOD_RANGE = 350;
 
-    /** This class represents a null expression. */
-    public static class Null extends TemporalExpression {
-        public Calendar first(Calendar cal) {
-            return null;
-        }
-        public boolean includesDate(Calendar cal) {
-            return false;
-        }
-        public Calendar next(Calendar cal) {
-            return null;
-        }
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
-        }
-    }
+    /** A temporal expression that represents a range of dates. */
+    public static class DateRange extends TemporalExpression {
+        protected final org.ofbiz.base.util.DateRange range;
 
-    /** This class represents a mathematical union of all of its
-     * member expressions. */
-    public static class Union extends TemporalExpression {
-        protected final Set<TemporalExpression> expressionSet;
+        public DateRange(Date date) {
+            this(date, date);
+        }
 
-        public Union(Set<TemporalExpression> expressionSet) {
-            if (expressionSet == null) {
-                throw new IllegalArgumentException("expressionSet argument cannot be null");
-            }
-            this.expressionSet = expressionSet;
-            if (containsExpression(this)) {
-                throw new IllegalArgumentException("recursive expression");
-            }
-            if (this.expressionSet.size() > 0) {
-                TemporalExpression that = this.expressionSet.iterator().next();
-                if (this.compareTo(that) > 0) {
-                    this.sequence = that.sequence;
-                    this.subSequence = that.subSequence;
-                }
-            }
+        public DateRange(Date start, Date end) {
+            this.range = new org.ofbiz.base.util.DateRange(start, end);
+            this.sequence = SEQUENCE_DATE_RANGE;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                return this.expressionSet.equals(((Union) obj).expressionSet);
-            } catch (Exception e) {}
-            return false;
-        }
-
-        public String toString() {
-            return super.toString() + ", size = " + this.expressionSet.size();
-        }
-
-        public boolean includesDate(Calendar cal) {
-            for (TemporalExpression expression : this.expressionSet) {
-                if (expression.includesDate(cal)) {
-                    return true;
-                }
-            }
+                return this.range.equals(((DateRange) obj).range);
+            } catch (ClassCastException e) {}
             return false;
         }
 
+        @Override
         public Calendar first(Calendar cal) {
-            for (TemporalExpression expression : this.expressionSet) {
-                Calendar first = expression.first(cal);
-                if (first != null && includesDate(first)) {
-                    return first;
-                }
-            }
-            return null;
-        }
-
-        public Calendar next(Calendar cal) {
-            Calendar result = null;
-            for (TemporalExpression expression : this.expressionSet) {
-                Calendar next = expression.next(cal);
-                if (next != null && includesDate(next)) {
-                    if (result == null || next.before(result)) {
-                        result = next;
-                    }
-                }
-            }
-            return result;
+            return includesDate(cal) ? cal : null;
         }
 
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
+        /** Returns the contained <code>org.ofbiz.base.util.DateRange</code>.
+         * @return The contained <code>org.ofbiz.base.util.DateRange</code>
+         */
+        public org.ofbiz.base.util.DateRange getDateRange() {
+            return this.range;
         }
 
-        public Set<Date> getRange(org.ofbiz.base.util.DateRange range, Calendar cal) {
-            Set<Date> rawSet = new TreeSet<Date>();
-            Set<Date> finalSet = new TreeSet<Date>();
-            for (TemporalExpression expression : this.expressionSet) {
-                rawSet.addAll(expression.getRange(range, cal));
-            }
-            Calendar checkCal = (Calendar) cal.clone();
-            for (Date date : rawSet) {
-                checkCal.setTime(date);
-                if (includesDate(checkCal)) {
-                    finalSet.add(date);
-                }
-            }
-            return finalSet;
+        @Override
+        public boolean includesDate(Calendar cal) {
+            return this.range.includesDate(cal.getTime());
         }
 
-        /** Returns the member expression <code>Set</code>. The
-         * returned set is unmodifiable.
-         * @return The member expression <code>Set</code>
-         */
-        public Set<TemporalExpression> getExpressionSet() {
-            return Collections.unmodifiableSet(this.expressionSet);
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            return includesDate(cal) ? cal : null;
         }
 
-        protected boolean containsExpression(TemporalExpression expression) {
-            for (TemporalExpression setItem : this.expressionSet) {
-                if (setItem.containsExpression(expression)) {
-                    return true;
-                }
-            }
-            return false;
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.range.start() + ", end = " + this.range.end();
         }
     }
 
-    /** This class represents a mathematical intersection of all of its
-     * member expressions. */
-    public static class Intersection extends TemporalExpression {
-        protected final Set<TemporalExpression> expressionSet;
+    /** A temporal expression that represents a day in the month. */
+    public static class DayInMonth extends TemporalExpression {
+        protected final int dayOfWeek;
+        protected final int occurrence;
 
-        public Intersection(Set<TemporalExpression> expressionSet) {
-            if (expressionSet == null) {
-                throw new IllegalArgumentException("expressionSet argument cannot be null");
+        /**
+         * @param dayOfWeek An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         * @param occurrence An integer in the range of -5 to 5, excluding zero
+         */
+        public DayInMonth(int dayOfWeek, int occurrence) {
+            if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid day argument");
             }
-            this.expressionSet = expressionSet;
-            if (containsExpression(this)) {
-                throw new IllegalArgumentException("recursive expression");
+            if (occurrence < -5 || occurrence == 0 || occurrence > 5) {
+                throw new IllegalArgumentException("Invalid occurrence argument");
             }
-            if (this.expressionSet.size() > 0) {
-                TemporalExpression that = this.expressionSet.iterator().next();
-                if (this.compareTo(that) > 0) {
-                    this.sequence = that.sequence;
-                    this.subSequence = that.subSequence;
-                }
+            this.dayOfWeek = dayOfWeek;
+            this.occurrence = occurrence;
+            int result = occurrence;
+            if (result < 0) {
+                // Make negative values a higher sequence
+                // Example: Last Monday should come after first Monday
+                result += 11;
             }
+            this.sequence = SEQUENCE_DAY_IN_MONTH + (result * 10) + dayOfWeek;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        protected Calendar alignDayOfWeek(Calendar cal) {
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+            if (this.occurrence > 0) {
+                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                    cal.add(Calendar.DAY_OF_MONTH, 1);
+                }
+                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence - 1) * 7);
+            } else {
+                cal.add(Calendar.MONTH, 1);
+                cal.add(Calendar.DAY_OF_MONTH, -1);
+                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                    cal.add(Calendar.DAY_OF_MONTH, -1);
+                }
+                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence + 1) * 7);
+            }
+            return cal;
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                return this.expressionSet.equals(((Intersection) obj).expressionSet);
-            } catch (Exception e) {}
+                DayInMonth that = (DayInMonth) obj;
+                return this.dayOfWeek == that.dayOfWeek && this.occurrence == that.occurrence;
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", size = " + this.expressionSet.size();
+        @Override
+        public Calendar first(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            Calendar first = alignDayOfWeek((Calendar) cal.clone());
+            if (first.before(cal)) {
+                first.set(Calendar.DAY_OF_MONTH, 1);
+                if (first.get(Calendar.MONTH) == month) {
+                    first.add(Calendar.MONTH, 1);
+                }
+                alignDayOfWeek(first);
+            }
+            return first;
+        }
+
+        /** Returns the day of week in this expression.
+         * @return The day of week in this expression
+         */
+        public int getDayOfWeek() {
+            return this.dayOfWeek;
+        }
+
+        /** Returns the occurrence in this expression.
+         * @return The occurrence in this expression
+         */
+        public int getOccurrence() {
+            return this.occurrence;
         }
 
+        @Override
         public boolean includesDate(Calendar cal) {
-            for (TemporalExpression expression : this.expressionSet) {
-                if (!expression.includesDate(cal)) {
-                    return false;
-                }
+            if (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                return false;
             }
-            return true;
+            int month = cal.get(Calendar.MONTH);
+            int dom = cal.get(Calendar.DAY_OF_MONTH);
+            Calendar next = (Calendar) cal.clone();
+            alignDayOfWeek(next);
+            return dom == next.get(Calendar.DAY_OF_MONTH) && next.get(Calendar.MONTH) == month;
         }
 
-        public Calendar first(Calendar cal) {
-            Calendar first = (Calendar) cal.clone();
-            for (TemporalExpression expression : this.expressionSet) {
-                first = expression.first(first);
-                if (first == null) {
-                    return null;
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            int month = cal.get(Calendar.MONTH);
+            Calendar next = alignDayOfWeek((Calendar) cal.clone());
+            if (next.before(cal) || next.equals(cal)) {
+                next.set(Calendar.DAY_OF_MONTH, 1);
+                if (next.get(Calendar.MONTH) == month) {
+                    next.add(Calendar.MONTH, 1);
                 }
+                alignDayOfWeek(next);
             }
-            if (includesDate(first)) {
-                return first;
-            } else {
-                return null;
-            }
+            return next;
         }
 
-        public Calendar next(Calendar cal) {
-            Calendar next = (Calendar) cal.clone();
-            for (TemporalExpression expression : this.expressionSet) {
-                next = expression.next(next);
-                if (next == null) {
-                    return null;
-                }
+        @Override
+        public String toString() {
+            return super.toString() + ", dayOfWeek = " + this.dayOfWeek + ", occurrence = " + this.occurrence;
+        }
+    }
+
+    /** A temporal expression that represents a day of month range. */
+    public static class DayOfMonthRange extends TemporalExpression {
+        protected final int end;
+        protected final int start;
+
+        public DayOfMonthRange(int dom) {
+            this(dom, dom);
+        }
+
+        /**
+         * @param start An integer in the range of 1 to 31
+         * @param end An integer in the range of 1 to 31
+         */
+        public DayOfMonthRange(int start, int end) {
+            if (start < 1 || start > end) {
+                throw new IllegalArgumentException("Invalid start argument");
             }
-            if (includesDate(next)) {
-                return next;
-            } else {
-                return null;
+            if (end < 1 || end > 31) {
+                throw new IllegalArgumentException("Invalid end argument");
+            }
+            this.sequence = SEQUENCE_DOM_RANGE + start;
+            this.start = start;
+            this.end = end;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
         public void accept(TemporalExpressionVisitor visitor) {
             visitor.visit(this);
         }
 
-        public Set<Date> getRange(org.ofbiz.base.util.DateRange range, Calendar cal) {
-            Set<Date> finalSet = new TreeSet<Date>();
-            Set<Date> rawSet = new TreeSet<Date>();
-            Date last = range.start();
-            Calendar next = first(cal);
-            while (next != null && range.includesDate(next.getTime())) {
-                last = next.getTime();
-                rawSet.add(last);
-                next = next(next);
-                if (next != null && last.equals(next.getTime())) {
-                    break;
-                }
-            }
-            Calendar checkCal = (Calendar) cal.clone();
-            for (Date date : rawSet) {
-                checkCal.setTime(date);
-                if (includesDate(checkCal)) {
-                    finalSet.add(date);
-                }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
             }
-            return finalSet;
+            try {
+                DayOfMonthRange that = (DayOfMonthRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (ClassCastException e) {}
+            return false;
         }
 
-        /** Returns the member expression <code>Set</code>. The
-         * returned set is unmodifiable.
-         * @return The member expression <code>Set</code>
+        @Override
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            while (!includesDate(first)) {
+                first.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return first;
+        }
+
+        /** Returns the ending day of this range.
+         * @return The ending day of this range
          */
-        public Set<TemporalExpression> getExpressionSet() {
-            return Collections.unmodifiableSet(this.expressionSet);
+        public int getEndDay() {
+            return this.end;
         }
 
-        protected boolean containsExpression(TemporalExpression expression) {
-            for (TemporalExpression setItem : this.expressionSet) {
-                if (setItem.containsExpression(expression)) {
+        /** Returns the starting day of this range.
+         * @return The starting day of this range
+         */
+        public int getStartDay() {
+            return this.start;
+        }
+
+        @Override
+        public boolean includesDate(Calendar cal) {
+            int dom = cal.get(Calendar.DAY_OF_MONTH);
+            return dom >= this.start && dom <= this.end;
+        }
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = (Calendar) cal.clone();
+            next.add(Calendar.DAY_OF_MONTH, 1);
+            while (!includesDate(next)) {
+                next.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return next;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+    }
+
+    /** A temporal expression that represents a day of week range. */
+    public static class DayOfWeekRange extends TemporalExpression {
+        protected final int end;
+        protected final int start;
+
+        public DayOfWeekRange(int dow) {
+            this(dow, dow);
+        }
+
+        /**
+         * @param start An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         * @param end An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         */
+        public DayOfWeekRange(int start, int end) {
+            if (start < Calendar.SUNDAY || start > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid start argument");
+            }
+            if (end < Calendar.SUNDAY || end > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid end argument");
+            }
+            this.sequence = SEQUENCE_DOW_RANGE + start;
+            this.start = start;
+            this.end = end;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                DayOfWeekRange that = (DayOfWeekRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (ClassCastException e) {}
+            return false;
+        }
+
+        @Override
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            while (!includesDate(first)) {
+                first.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return first;
+        }
+
+        /** Returns the ending day of this range.
+         * @return The ending day of this range
+         */
+        public int getEndDay() {
+            return this.end;
+        }
+
+        /** Returns the starting day of this range.
+         * @return The starting day of this range
+         */
+        public int getStartDay() {
+            return this.start;
+        }
+
+        @Override
+        public boolean includesDate(Calendar cal) {
+            int dow = cal.get(Calendar.DAY_OF_WEEK);
+            if (dow == this.start || dow == this.end) {
+                return true;
+            }
+            Calendar compareCal = (Calendar) cal.clone();
+            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.start) {
+                compareCal.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.end) {
+                if (compareCal.get(Calendar.DAY_OF_WEEK) == dow) {
                     return true;
                 }
+                compareCal.add(Calendar.DAY_OF_MONTH, 1);
             }
             return false;
         }
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = (Calendar) cal.clone();
+            if (includesDate(next)) {
+                if (context.dayBumped) {
+                    return next;
+                }
+                next.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            while (!includesDate(next)) {
+                next.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            if (cal.get(Calendar.MONTH) != next.get(Calendar.MONTH)) {
+                context.monthBumped = true;
+            }
+            return next;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
     }
 
-    /** This class represents a difference of two temporal expressions. */
+    /** A temporal expression that represents a difference of two temporal expressions. */
     public static class Difference extends TemporalExpression {
-        protected final TemporalExpression included;
         protected final TemporalExpression excluded;
+        protected final TemporalExpression included;
 
         public Difference(TemporalExpression included, TemporalExpression excluded) {
             if (included == null) {
@@ -298,15 +459,23 @@
             if (containsExpression(this)) {
                 throw new IllegalArgumentException("recursive expression");
             }
-            if (this.compareTo(included) > 0) {
-                this.sequence = included.sequence;
-                this.subSequence = included.subSequence;
-            }
+            this.sequence = included.sequence;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        protected boolean containsExpression(TemporalExpression expression) {
+            return this.included.containsExpression(expression) || this.excluded.containsExpression(expression);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
@@ -314,18 +483,11 @@
             try {
                 Difference that = (Difference) obj;
                 return this.included.equals(that.included) && this.excluded.equals(that.excluded);
-            } catch (Exception e) {}
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", included = " + this.included + ", excluded = " + this.excluded;
-        }
-
-        public boolean includesDate(Calendar cal) {
-            return this.included.includesDate(cal) && !this.excluded.includesDate(cal);
-        }
-
+        @Override
         public Calendar first(Calendar cal) {
             Calendar first = this.included.first(cal);
             while (first != null && this.excluded.includesDate(first)) {
@@ -334,31 +496,6 @@
             return first;
         }
 
-        public Calendar next(Calendar cal) {
-            Calendar next = this.included.next(cal);
-            while (next != null && this.excluded.includesDate(next)) {
-                next = this.included.next(next);
-            }
-            return next;
-        }
-
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
-        }
-
-        public Set<Date> getRange(org.ofbiz.base.util.DateRange range, Calendar cal) {
-            Set<Date> finalSet = new TreeSet<Date>();
-            Set<Date> rawSet = this.included.getRange(range, cal);
-            Calendar checkCal = (Calendar) cal.clone();
-            for (Date date : rawSet) {
-                checkCal.setTime(date);
-                if (!this.excluded.includesDate(checkCal)) {
-                    finalSet.add(date);
-                }
-            }
-            return finalSet;
-        }
-
         /** Returns the excluded expression.
          * @return The excluded <code>TemporalExpression</code>
          */
@@ -373,742 +510,915 @@
             return this.included;
         }
 
-        protected boolean containsExpression(TemporalExpression expression) {
-            return this.included.containsExpression(expression) || this.excluded.containsExpression(expression);
+        @Override
+        public boolean includesDate(Calendar cal) {
+            return this.included.includesDate(cal) && !this.excluded.includesDate(cal);
+        }
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = this.included.next(cal, context);
+            while (next != null && this.excluded.includesDate(next)) {
+                next = this.included.next(next, context);
+            }
+            return next;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", included = " + this.included + ", excluded = " + this.excluded;
         }
     }
 
-    /** A temporal expression that represents a range of dates. */
-    public static class DateRange extends TemporalExpression {
-        protected final org.ofbiz.base.util.DateRange range;
+    /** A temporal expression that represents a frequency. */
+    public static class Frequency extends TemporalExpression {
+        protected final int freqCount;
+        protected final int freqType;
+        protected final Date start;
 
-        public DateRange(Date start, Date end) {
-            this.sequence = 1000;
-            this.range = new org.ofbiz.base.util.DateRange(start, end);
+        /**
+         * @param start Starting date, defaults to current system time
+         * @param freqType One of the following integer values: <code>Calendar.SECOND
+         * Calendar.MINUTE Calendar.HOUR Calendar.DAY_OF_MONTH Calendar.MONTH
+         * Calendar.YEAR</code>
+         * @param freqCount A positive integer
+         */
+        public Frequency(Date start, int freqType, int freqCount) {
+            if (freqType != Calendar.SECOND && freqType != Calendar.MINUTE
+                    && freqType != Calendar.HOUR && freqType != Calendar.DAY_OF_MONTH
+                    && freqType != Calendar.MONTH && freqType != Calendar.YEAR) {
+                throw new IllegalArgumentException("Invalid freqType argument");
+            }
+            if (freqCount < 1) {
+                throw new IllegalArgumentException("freqCount argument must be a positive integer");
+            }
+            if (start != null) {
+                this.start = start;
+            } else {
+                this.start = new Date();
+            }
+            this.sequence = SEQUENCE_FREQ + freqType;
+            this.freqType = freqType;
+            this.freqCount = freqCount;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                return this.range.equals(((DateRange) obj).range);
-            } catch (Exception e) {}
+                Frequency that = (Frequency) obj;
+                return this.start.equals(that.start) && this.freqType == that.freqType && this.freqCount == that.freqCount;
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", start = " + this.range.start() + ", end = " + this.range.end();
-        }
-
-        public boolean includesDate(Calendar cal) {
-            return this.range.includesDate(cal.getTime());
-        }
-
+        @Override
         public Calendar first(Calendar cal) {
-            return includesDate(cal) ? cal : null;
+            Calendar first = prepareCal(cal);
+            while (first.before(cal)) {
+                first.add(this.freqType, this.freqCount);
+            }
+            return first;
         }
 
-        public Calendar next(Calendar cal) {
-            return includesDate(cal) ? cal : null;
+        /** Returns the frequency count of this expression.
+         * @return The frequency count of this expression
+         */
+        public int getFreqCount() {
+            return this.freqCount;
         }
 
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
+        /** Returns the frequency type of this expression.
+         * @return The frequency type of this expression
+         */
+        public int getFreqType() {
+            return this.freqType;
         }
 
-        /** Returns the contained <code>org.ofbiz.base.util.DateRange</code>.
-         * @return The contained <code>org.ofbiz.base.util.DateRange</code>
+        /** Returns the start date of this expression.
+         * @return The start date of this expression
          */
-        public org.ofbiz.base.util.DateRange getDateRange() {
-            return this.range;
+        public Date getStartDate() {
+            return (Date) this.start.clone();
         }
-    }
 
-    /** A temporal expression that represents a time of day range. */
-    public static class TimeOfDayRange extends TemporalExpression {
-        protected final String startStr;
-        protected final String endStr;
-        protected final int interval;
-        protected final int count;
-        protected final int startSecs;
-        protected final int startMins;
-        protected final int startHrs;
-        protected final int endSecs;
-        protected final int endMins;
-        protected final int endHrs;
-
-        /**
-         * @param start A time String in the form of hh:mm:ss (24 hr clock)
-         * @param end A time String in the form of hh:mm:ss (24 hr clock)
-         * @param interval The range interval - must be one of <code>
-         * Calendar.SECOND Calendar.MINUTE Calendar.HOUR_OF_DAY</code>
-         * @param count The interval count - must be greater than zero
-         */
-        public TimeOfDayRange(String start, String end, int interval, int count) {
-            if (start == null || start.length() == 0) {
-                throw new IllegalArgumentException("start argument cannot be null or empty");
-            }
-            if (end == null || end.length() == 0) {
-                throw new IllegalArgumentException("end argument cannot be null or empty");
-            }
-            if (interval != Calendar.SECOND && interval != Calendar.MINUTE && interval != Calendar.HOUR_OF_DAY) {
-                throw new IllegalArgumentException("invalid interval argument");
-            }
-            if (count < 1) {
-                throw new IllegalArgumentException("invalid count argument");
-            }
-            this.startStr = start;
-            this.endStr = end;
-            this.interval = interval;
-            this.count = count;
-            String strArray[] = this.startStr.split(":");
-            if (strArray.length == 0 || strArray.length > 3) {
-                throw new IllegalArgumentException("Invalid start time argument");
-            }
-            this.startHrs = Integer.valueOf(strArray[0]);
-            this.startMins = strArray.length > 1 ? Integer.valueOf(strArray[1]) : 0;
-            this.startSecs = strArray.length > 2 ? Integer.valueOf(strArray[2]) : 0;
-            if (this.startHrs > 23 || this.startMins > 59 || this.startSecs > 59) {
-                throw new IllegalArgumentException("Invalid start time argument");
-            }
-            strArray = this.endStr.split(":");
-            if (strArray.length == 0 || strArray.length > 3) {
-                throw new IllegalArgumentException("Invalid end time argument");
-            }
-            this.endHrs = Integer.valueOf(strArray[0]);
-            this.endMins = strArray.length > 1 ? Integer.valueOf(strArray[1]) : 0;
-            this.endSecs = strArray.length > 2 ? Integer.valueOf(strArray[2]) : 0;
-            if (this.endHrs > 23 || this.endMins > 59 || this.endSecs > 59) {
-                throw new IllegalArgumentException("Invalid end time argument");
-            }
-            this.sequence = 600;
-            this.subSequence = (this.startHrs * 4000) + (this.startMins * 60) + this.startSecs;
-            if (Debug.verboseOn()) {
-                Debug.logVerbose("Created " + this, module);
-            }
+        @Override
+        public boolean includesDate(Calendar cal) {
+            Calendar next = first(cal);
+            return next.equals(cal);
         }
 
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = first(cal);
+            if (next.equals(cal)) {
+                next.add(this.freqType, this.freqCount);
             }
-            try {
-                TimeOfDayRange that = (TimeOfDayRange) obj;
-                return this.startStr.equals(that.startStr) && this.endStr.equals(that.endStr);
-            } catch (Exception e) {}
-            return false;
-        }
-
-        public String toString() {
-            return super.toString() + ", start = " + this.startStr + ", end = " + this.endStr
-            + ", interval = " + this.interval + ", count = " + this.count;
+            return next;
         }
 
-        public boolean includesDate(Calendar cal) {
-            long millis = cal.getTimeInMillis();
-            Calendar startCal = setStart(cal);
-            Calendar endCal = setEnd(startCal);
-            if (endCal.before(startCal)) {
-                endCal.add(Calendar.DAY_OF_MONTH, 1);
+        protected Calendar prepareCal(Calendar cal) {
+            // Performs a "sane" skip forward in time - avoids time consuming loops
+            // like incrementing every second from Jan 1 2000 until today
+            Calendar skip = (Calendar) cal.clone();
+            skip.setTime(this.start);
+            long deltaMillis = cal.getTimeInMillis() - this.start.getTime();
+            if (deltaMillis < 1000) {
+                return skip;
             }
-            long startMillis = startCal.getTimeInMillis();
-            long endMillis = endCal.getTimeInMillis();
-            return millis >= startMillis && millis <= endMillis;
-        }
-
-        public Calendar first(Calendar cal) {
-            if (includesDate(cal)) {
-                return cal;
+            long divisor = deltaMillis;
+            if (this.freqType == Calendar.DAY_OF_MONTH) {
+                divisor = 86400000;
+            } else if (this.freqType == Calendar.HOUR) {
+                divisor = 3600000;
+            } else if (this.freqType == Calendar.MINUTE) {
+                divisor = 60000;
+            } else if (this.freqType == Calendar.SECOND) {
+                divisor = 1000;
+            } else {
+                return skip;
             }
-            return next(cal);
-        }
-
-        public Calendar next(Calendar cal) {
-            Calendar next = (Calendar) cal.clone();
-            next.add(this.interval, this.count);
-            if (!includesDate(next)) {
-                Calendar last = next;
-                next = setStart(next);
-                if (next.before(last)) {
-                    next.add(Calendar.DAY_OF_MONTH, 1);
-                }
+            float units = deltaMillis / divisor;
+            units = (units / this.freqCount) * this.freqCount;
+            skip.add(this.freqType, (int)units);
+            while (skip.after(cal)) {
+                skip.add(this.freqType, -this.freqCount);
             }
-            return next;
-        }
-
-        public int getCount() {
-            return this.count;
-        }
-
-        public int getEndHours() {
-            return this.endHrs;
-        }
-
-        public int getEndMins() {
-            return this.endMins;
-        }
-
-        public int getEndSecs() {
-            return this.endSecs;
-        }
-
-        public int getInterval() {
-            return this.interval;
-        }
-
-        public int getStartHours() {
-            return this.startHrs;
-        }
-
-        public int getStartMins() {
-            return this.startMins;
-        }
-
-        public int getStartSecs() {
-            return this.startSecs;
+            return skip;
         }
 
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", freqType = " + this.freqType + ", freqCount = " + this.freqCount;
         }
+    }
 
-        protected Calendar setCalendar(Calendar cal, int hrs, int mins, int secs) {
-            Calendar newCal = (Calendar) cal.clone();
-            newCal.set(Calendar.MILLISECOND, 0);
-            newCal.set(Calendar.SECOND, secs);
-            newCal.set(Calendar.MINUTE, mins);
-            newCal.set(Calendar.HOUR_OF_DAY, hrs);
-            return newCal;
-        }
 
-        protected Calendar setStart(Calendar cal) {
-            return setCalendar(cal, this.startHrs, this.startMins, this.startSecs);
-        }
+    /** A temporal expression that represents an hour range. */
+    public static class HourRange extends TemporalExpression {
+        protected final int end;
+        protected final int start;
 
-        protected Calendar setEnd(Calendar cal) {
-            return setCalendar(cal, this.endHrs, this.endMins, this.endSecs);
+        /**
+         * @param hour An integer in the range of 0 to 23.
+         */
+        public HourRange(int hour) {
+            this(hour, hour);
         }
-    }
-
-    /** A temporal expression that represents a day of week range. */
-    public static class DayOfWeekRange extends TemporalExpression {
-        protected final int start;
-        protected final int end;
 
         /**
-         * @param start An integer in the range of <code>Calendar.SUNDAY</code>
-         * to <code>Calendar.SATURDAY</code>
-         * @param end An integer in the range of <code>Calendar.SUNDAY</code>
-         * to <code>Calendar.SATURDAY</code>
+         * @param start An integer in the range of 0 to 23.
+         * @param end An integer in the range of 0 to 23.
          */
-        public DayOfWeekRange(int start, int end) {
-            if (start < Calendar.SUNDAY || start > Calendar.SATURDAY) {
+        public HourRange(int start, int end) {
+            if (start < 0 || start > 23) {
                 throw new IllegalArgumentException("Invalid start argument");
             }
-            if (end < Calendar.SUNDAY || end > Calendar.SATURDAY) {
+            if (end < 0 || end > 23) {
                 throw new IllegalArgumentException("Invalid end argument");
             }
-            this.sequence = 500;
-            this.subSequence = start;
             this.start = start;
             this.end = end;
+            this.sequence = SEQUENCE_HOUR_RANGE + start;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                DayOfWeekRange that = (DayOfWeekRange) obj;
+                HourRange that = (HourRange) obj;
                 return this.start == that.start && this.end == that.end;
-            } catch (Exception e) {}
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        @Override
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            while (!includesDate(first)) {
+                first.add(Calendar.HOUR_OF_DAY, 1);
+            }
+            return first;
+        }
+
+        /** Returns the ending hour of this range.
+         * @return The ending hour of this range
+         */
+        public int getEndHour() {
+            return this.end;
         }
 
+        public Set<Integer> getHourRangeAsSet() {
+            Set<Integer> rangeSet = new TreeSet<Integer>();
+            if (this.start == this.end) {
+                rangeSet.add(this.start);
+            } else {
+                Calendar cal = Calendar.getInstance();
+                cal.set(Calendar.HOUR_OF_DAY, this.start);
+                while (cal.get(Calendar.HOUR_OF_DAY) != this.end) {
+                    rangeSet.add(cal.get(Calendar.HOUR_OF_DAY));
+                    cal.add(Calendar.HOUR_OF_DAY, 1);
+                }
+            }
+            return rangeSet;
+        }
+
+        /** Returns the starting hour of this range.
+         * @return The starting hour of this range
+         */
+        public int getStartHour() {
+            return this.start;
+        }
+
+        @Override
         public boolean includesDate(Calendar cal) {
-            int dow = cal.get(Calendar.DAY_OF_WEEK);
-            if (dow == this.start || dow == this.end) {
+            int hour = cal.get(Calendar.HOUR_OF_DAY);
+            if (hour == this.start || hour == this.end) {
                 return true;
             }
             Calendar compareCal = (Calendar) cal.clone();
-            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.start) {
-                compareCal.add(Calendar.DAY_OF_MONTH, 1);
-            }
-            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.end) {
-                if (compareCal.get(Calendar.DAY_OF_WEEK) == dow) {
+            compareCal.set(Calendar.HOUR_OF_DAY, this.start);
+            while (compareCal.get(Calendar.HOUR_OF_DAY) != this.end) {
+                if (compareCal.get(Calendar.HOUR_OF_DAY) == hour) {
                     return true;
                 }
-                compareCal.add(Calendar.DAY_OF_MONTH, 1);
+                compareCal.add(Calendar.HOUR_OF_DAY, 1);
             }
             return false;
         }
 
-        public Calendar first(Calendar cal) {
-            Calendar first = (Calendar) cal.clone();
-            while (!includesDate(first)) {
-                first.add(Calendar.DAY_OF_MONTH, 1);
-            }
-            return setStartOfDay(first);
-        }
 
-        public Calendar next(Calendar cal) {
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
             Calendar next = (Calendar) cal.clone();
-            next.add(Calendar.DAY_OF_MONTH, 1);
+            if (includesDate(next)) {
+                if (context.hourBumped) {
+                    return next;
+                }
+                next.add(Calendar.HOUR_OF_DAY, 1);
+            }
             while (!includesDate(next)) {
-                next.add(Calendar.DAY_OF_MONTH, 1);
+                next.add(Calendar.HOUR_OF_DAY, 1);
             }
-            return setStartOfDay(next);
-        }
-
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
-        }
-
-        /** Returns the starting day of this range.
-         * @return The starting day of this range
-         */
-        public int getStartDay() {
-            return this.start;
+            if (cal.get(Calendar.DAY_OF_MONTH) != next.get(Calendar.DAY_OF_MONTH)) {
+                context.dayBumped = true;
+            }
+            return next;
         }
 
-        /** Returns the ending day of this range.
-         * @return The ending day of this range
-         */
-        public int getEndDay() {
-            return this.end;
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
         }
     }
 
-    /** A temporal expression that represents a month range. */
-    public static class MonthRange extends TemporalExpression {
-        protected final int start;
-        protected final int end;
+    /** A temporal expression that represents a mathematical intersection of all of its
+     * member expressions. */
+    public static class Intersection extends TemporalExpression {
+        protected final Set<TemporalExpression> expressionSet;
 
-        /**
-         * @param start An integer in the range of <code>Calendar.JANUARY</code>
-         * to <code>Calendar.UNDECIMBER</code>
-         * @param end An integer in the range of <code>Calendar.JANUARY</code>
-         * to <code>Calendar.UNDECIMBER</code>
-         */
-        public MonthRange(int start, int end) {
-            if (start < Calendar.JANUARY || start > Calendar.UNDECIMBER) {
-                throw new IllegalArgumentException("Invalid start argument");
+        public Intersection(Set<TemporalExpression> expressionSet) {
+            if (expressionSet == null) {
+                throw new IllegalArgumentException("expressionSet argument cannot be null");
             }
-            if (end < Calendar.JANUARY || end > Calendar.UNDECIMBER) {
-                throw new IllegalArgumentException("Invalid end argument");
+            this.expressionSet = expressionSet;
+            if (containsExpression(this)) {
+                throw new IllegalArgumentException("recursive expression");
+            }
+            if (this.expressionSet.size() > 0) {
+                // Aggregate member expression sequences in a way that will
+                // ensure the proper evaluation sequence for the entire collection
+                int result = 0;
+                TemporalExpression[] exprArray = this.expressionSet.toArray(new TemporalExpression[this.expressionSet.size()]);
+                for (int i = exprArray.length - 1; i >= 0; i--) {
+                    result *= 10;
+                    result += exprArray[i].sequence;
+                }
+                this.sequence = result;
             }
-            this.sequence = 200;
-            this.subSequence = start;
-            this.start = start;
-            this.end = end;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        protected boolean containsExpression(TemporalExpression expression) {
+            for (TemporalExpression setItem : this.expressionSet) {
+                if (setItem.containsExpression(expression)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                MonthRange that = (MonthRange) obj;
-                return this.start == that.start && this.end == that.end;
-            } catch (Exception e) {}
+                return this.expressionSet.equals(((Intersection) obj).expressionSet);
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", start = " + this.start + ", end = " + this.end;
-        }
-
-        public boolean includesDate(Calendar cal) {
-            int month = cal.get(Calendar.MONTH);
-            if (month == this.start || month == this.end) {
-                return true;
-            }
-            Calendar compareCal = (Calendar) cal.clone();
-            while (compareCal.get(Calendar.MONTH) != this.start) {
-                compareCal.add(Calendar.MONTH, 1);
-            }
-            while (compareCal.get(Calendar.MONTH) != this.end) {
-                if (compareCal.get(Calendar.MONTH) == month) {
-                    return true;
+        @Override
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            for (TemporalExpression expression : this.expressionSet) {
+                first = expression.first(first);
+                if (first == null) {
+                    return null;
                 }
-                compareCal.add(Calendar.MONTH, 1);
             }
-            return false;
+            if (includesDate(first)) {
+                return first;
+            } else {
+                return null;
+            }
         }
 
-        public Calendar first(Calendar cal) {
-            Calendar first = (Calendar) cal.clone();
-            first.set(Calendar.DAY_OF_MONTH, 1);
-            while (!includesDate(first)) {
-                first.add(Calendar.MONTH, 1);
+        /** Returns the member expression <code>Set</code>. The
+         * returned set is unmodifiable.
+         * @return The member expression <code>Set</code>
+         */
+        public Set<TemporalExpression> getExpressionSet() {
+            return Collections.unmodifiableSet(this.expressionSet);
+        }
+
+        @Override
+        public boolean includesDate(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                if (!expression.includesDate(cal)) {
+                    return false;
+                }
             }
-            return first;
+            return true;
         }
 
-        public Calendar next(Calendar cal) {
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
             Calendar next = (Calendar) cal.clone();
-            next.set(Calendar.DAY_OF_MONTH, 1);
-            next.add(Calendar.MONTH, 1);
-            while (!includesDate(next)) {
-                next.add(Calendar.MONTH, 1);
+            for (TemporalExpression expression : this.expressionSet) {
+                next = expression.next(next, context);
+                if (next == null) {
+                    return null;
+                }
             }
             return next;
         }
 
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
+        @Override
+        public String toString() {
+            return super.toString() + ", size = " + this.expressionSet.size();
         }
+    }
 
-        /** Returns the starting month of this range.
-         * @return The starting month of this range
-         */
-        public int getStartMonth() {
-            return this.start;
-        }
+    /** A temporal expression that represents a minute range. */
+    public static class MinuteRange extends TemporalExpression {
+        protected final int end;
+        protected final int start;
 
-        /** Returns the ending month of this range.
-         * @return The ending month of this range
+        /**
+         * @param hour An integer in the range of 0 to 59.
          */
-        public int getEndMonth() {
-            return this.end;
+        public MinuteRange(int minute) {
+            this(minute, minute);
         }
-    }
-
-    /** A temporal expression that represents a day of month range. */
-    public static class DayOfMonthRange extends TemporalExpression {
-        protected final int start;
-        protected final int end;
 
         /**
-         * @param start An integer in the range of 1 to 31
-         * @param end An integer in the range of 1 to 31
+         * @param start An integer in the range of 0 to 59.
+         * @param end An integer in the range of 0 to 59.
          */
-        public DayOfMonthRange(int start, int end) {
-            if (start < 1 || start > end) {
+        public MinuteRange(int start, int end) {
+            if (start < 0 || start > 59) {
                 throw new IllegalArgumentException("Invalid start argument");
             }
-            if (end < 1 || end > 31) {
+            if (end < 0 || end > 59) {
                 throw new IllegalArgumentException("Invalid end argument");
             }
-            this.sequence = 300;
-            this.subSequence = start;
             this.start = start;
             this.end = end;
+            this.sequence = SEQUENCE_MINUTE_RANGE + start;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                DayOfMonthRange that = (DayOfMonthRange) obj;
+                MinuteRange that = (MinuteRange) obj;
                 return this.start == that.start && this.end == that.end;
-            } catch (Exception e) {}
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", start = " + this.start + ", end = " + this.end;
-        }
-
-        public boolean includesDate(Calendar cal) {
-            int dom = cal.get(Calendar.DAY_OF_MONTH);
-            return dom >= this.start && dom <= this.end;
-        }
-
+        @Override
         public Calendar first(Calendar cal) {
-            Calendar first = setStartOfDay((Calendar) cal.clone());
+            Calendar first = (Calendar) cal.clone();
             while (!includesDate(first)) {
-                first.add(Calendar.DAY_OF_MONTH, 1);
+                first.add(Calendar.MINUTE, 1);
             }
             return first;
         }
 
-        public Calendar next(Calendar cal) {
-            Calendar next = setStartOfDay((Calendar) cal.clone());
-            next.add(Calendar.DAY_OF_MONTH, 1);
-            while (!includesDate(next)) {
-                next.add(Calendar.DAY_OF_MONTH, 1);
-            }
-            return next;
+        /** Returns the ending minute of this range.
+         * @return The ending minute of this range
+         */
+        public int getEndMinute() {
+            return this.end;
         }
 
-        public void accept(TemporalExpressionVisitor visitor) {
-            visitor.visit(this);
+        public Set<Integer> getMinuteRangeAsSet() {
+            Set<Integer> rangeSet = new TreeSet<Integer>();
+            if (this.start == this.end) {
+                rangeSet.add(this.start);
+            } else {
+                Calendar cal = Calendar.getInstance();
+                cal.set(Calendar.HOUR_OF_DAY, this.start);
+                while (cal.get(Calendar.HOUR_OF_DAY) != this.end) {
+                    rangeSet.add(cal.get(Calendar.HOUR_OF_DAY));
+                    cal.add(Calendar.HOUR_OF_DAY, 1);
+                }
+            }
+            return rangeSet;
         }
 
-        /** Returns the starting day of this range.
-         * @return The starting day of this range
+        /** Returns the starting minute of this range.
+         * @return The starting minute of this range
          */
-        public int getStartDay() {
+        public int getStartMinute() {
             return this.start;
         }
 
-        /** Returns the ending day of this range.
-         * @return The ending day of this range
-         */
-        public int getEndDay() {
-            return this.end;
+        @Override
+        public boolean includesDate(Calendar cal) {
+            int minute = cal.get(Calendar.MINUTE);
+            if (minute == this.start || minute == this.end) {
+                return true;
+            }
+            Calendar compareCal = (Calendar) cal.clone();
+            compareCal.set(Calendar.MINUTE, this.start);
+            while (compareCal.get(Calendar.MINUTE) != this.end) {
+                if (compareCal.get(Calendar.MINUTE) == minute) {
+                    return true;
+                }
+                compareCal.add(Calendar.MINUTE, 1);
+            }
+            return false;
+        }
+
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = (Calendar) cal.clone();
+            if (includesDate(next)) {
+                next.add(Calendar.MINUTE, 1);
+            }
+            while (!includesDate(next)) {
+                next.add(Calendar.MINUTE, 1);
+            }
+            if (cal.get(Calendar.HOUR_OF_DAY) != next.get(Calendar.HOUR_OF_DAY)) {
+                context.hourBumped = true;
+            }
+            return next;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
         }
     }
 
-    /** A temporal expression that represents a day in the month. */
-    public static class DayInMonth extends TemporalExpression {
-        protected final int dayOfWeek;
-        protected final int occurrence;
+    /** A temporal expression that represents a month range. */
+    public static class MonthRange extends TemporalExpression {
+        protected final int end;
+        protected final int start;
+
+        public MonthRange(int month) {
+            this(month, month);
+        }
 
         /**
-         * @param dayOfWeek An integer in the range of <code>Calendar.SUNDAY</code>
-         * to <code>Calendar.SATURDAY</code>
-         * @param occurrence An integer in the range of -5 to 5, excluding zero
+         * @param start An integer in the range of <code>Calendar.JANUARY</code>
+         * to <code>Calendar.UNDECIMBER</code>
+         * @param end An integer in the range of <code>Calendar.JANUARY</code>
+         * to <code>Calendar.UNDECIMBER</code>
          */
-        public DayInMonth(int dayOfWeek, int occurrence) {
-            if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) {
-                throw new IllegalArgumentException("Invalid day argument");
+        public MonthRange(int start, int end) {
+            if (start < Calendar.JANUARY || start > Calendar.UNDECIMBER) {
+                throw new IllegalArgumentException("Invalid start argument");
             }
-            if (occurrence < -5 || occurrence == 0 || occurrence > 5) {
-                throw new IllegalArgumentException("Invalid occurrence argument");
+            if (end < Calendar.JANUARY || end > Calendar.UNDECIMBER) {
+                throw new IllegalArgumentException("Invalid end argument");
             }
-            this.sequence = 400;
-            this.subSequence = dayOfWeek;
-            this.dayOfWeek = dayOfWeek;
-            this.occurrence = occurrence;
+            this.sequence = SEQUENCE_MONTH_RANGE + start;
+            this.start = start;
+            this.end = end;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                DayInMonth that = (DayInMonth) obj;
-                return this.dayOfWeek == that.dayOfWeek && this.occurrence == that.occurrence;
-            } catch (Exception e) {}
+                MonthRange that = (MonthRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", dayOfWeek = " + this.dayOfWeek + ", occurrence = " + this.occurrence;
-        }
-
-        public boolean includesDate(Calendar cal) {
-            if (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
-                return false;
-            }
-            int month = cal.get(Calendar.MONTH);
-            int dom = cal.get(Calendar.DAY_OF_MONTH);
-            Calendar next = (Calendar) cal.clone();
-            alignDayOfWeek(next);
-            return dom == next.get(Calendar.DAY_OF_MONTH) && next.get(Calendar.MONTH) == month;
-        }
-
+        @Override
         public Calendar first(Calendar cal) {
-            int month = cal.get(Calendar.MONTH);
-            Calendar first = setStartOfDay(alignDayOfWeek((Calendar) cal.clone()));
-            if (first.before(cal)) {
-                first.set(Calendar.DAY_OF_MONTH, 1);
-                if (first.get(Calendar.MONTH) == month) {
-                    first.add(Calendar.MONTH, 1);
-                }
-                alignDayOfWeek(first);
+            Calendar first = (Calendar) cal.clone();
+            first.set(Calendar.DAY_OF_MONTH, 1);
+            while (!includesDate(first)) {
+                first.add(Calendar.MONTH, 1);
             }
             return first;
         }
 
-        public Calendar next(Calendar cal) {
-            int month = cal.get(Calendar.MONTH);
-            Calendar next = setStartOfDay(alignDayOfWeek((Calendar) cal.clone()));
-            if (next.before(cal) || next.equals(cal)) {
-                next.set(Calendar.DAY_OF_MONTH, 1);
-                if (next.get(Calendar.MONTH) == month) {
-                    next.add(Calendar.MONTH, 1);
+        /** Returns the ending month of this range.
+         * @return The ending month of this range
+         */
+        public int getEndMonth() {
+            return this.end;
+        }
+
+        /** Returns the starting month of this range.
+         * @return The starting month of this range
+         */
+        public int getStartMonth() {
+            return this.start;
+        }
+
+        @Override
+        public boolean includesDate(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            if (month == this.start || month == this.end) {
+                return true;
+            }
+            Calendar compareCal = (Calendar) cal.clone();
+            while (compareCal.get(Calendar.MONTH) != this.start) {
+                compareCal.add(Calendar.MONTH, 1);
+            }
+            while (compareCal.get(Calendar.MONTH) != this.end) {
+                if (compareCal.get(Calendar.MONTH) == month) {
+                    return true;
                 }
-                alignDayOfWeek(next);
+                compareCal.add(Calendar.MONTH, 1);
+            }
+            return false;
+        }
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = (Calendar) cal.clone();
+            next.set(Calendar.DAY_OF_MONTH, 1);
+            next.add(Calendar.MONTH, 1);
+            while (!includesDate(next)) {
+                next.add(Calendar.MONTH, 1);
             }
             return next;
         }
 
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+    }
+
+    /** A temporal expression that represents a null expression. */
+    public static class Null extends TemporalExpression {
+        @Override
         public void accept(TemporalExpressionVisitor visitor) {
             visitor.visit(this);
         }
-
-        /** Returns the day of week in this expression.
-         * @return The day of week in this expression
-         */
-        public int getDayOfWeek() {
-            return this.dayOfWeek;
+        @Override
+        public Calendar first(Calendar cal) {
+            return null;
         }
-
-        /** Returns the occurrence in this expression.
-         * @return The occurrence in this expression
-         */
-        public int getOccurrence() {
-            return this.occurrence;
+        @Override
+        public boolean includesDate(Calendar cal) {
+            return false;
         }
-
-        protected Calendar alignDayOfWeek(Calendar cal) {
-            cal.set(Calendar.DAY_OF_MONTH, 1);
-            if (this.occurrence > 0) {
-                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
-                    cal.add(Calendar.DAY_OF_MONTH, 1);
-                }
-                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence - 1) * 7);
-            } else {
-                cal.add(Calendar.MONTH, 1);
-                cal.add(Calendar.DAY_OF_MONTH, -1);
-                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
-                    cal.add(Calendar.DAY_OF_MONTH, -1);
-                }
-                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence + 1) * 7);
-            }
-            return cal;
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            return null;
         }
     }
 
-    /** A temporal expression that represents a frequency. */
-    public static class Frequency extends TemporalExpression {
-        protected final Date start;
-        protected final int freqType;
-        protected final int freqCount;
+    /** A temporal expression that represents a time of day range.
+     * @deprecated
+     */
+    @Deprecated
+    public static class TimeOfDayRange extends TemporalExpression {
+        protected final int count;
+        protected final int endHrs;
+        protected final int endMins;
+        protected final int endSecs;
+        protected final String endStr;
+        protected final int interval;
+        protected final int startHrs;
+        protected final int startMins;
+        protected final int startSecs;
+        protected final String startStr;
 
         /**
-         * @param start Starting date, defaults to current system time
-         * @param freqType One of the following integer values: <code>Calendar.SECOND
-         * Calendar.MINUTE Calendar.HOUR Calendar.DAY_OF_MONTH Calendar.MONTH
-         * Calendar.YEAR</code>
-         * @param freqCount A positive integer
+         * @param start A time String in the form of hh:mm:ss (24 hr clock)
+         * @param end A time String in the form of hh:mm:ss (24 hr clock)
+         * @param interval The range interval - must be one of <code>
+         * Calendar.SECOND Calendar.MINUTE Calendar.HOUR_OF_DAY</code>
+         * @param count The interval count - must be greater than zero
          */
-        public Frequency(Date start, int freqType, int freqCount) {
-            if (freqType != Calendar.SECOND && freqType != Calendar.MINUTE
-                    && freqType != Calendar.HOUR && freqType != Calendar.DAY_OF_MONTH
-                    && freqType != Calendar.MONTH && freqType != Calendar.YEAR) {
-                throw new IllegalArgumentException("Invalid freqType argument");
+        public TimeOfDayRange(String start, String end, int interval, int count) {
+            if (UtilValidate.isEmpty(start)) {
+                throw new IllegalArgumentException("start argument cannot be null or empty");
             }
-            if (freqCount < 1) {
-                throw new IllegalArgumentException("freqCount argument must be a positive integer");
+            if (UtilValidate.isEmpty(end)) {
+                throw new IllegalArgumentException("end argument cannot be null or empty");
             }
-            if (start != null) {
-                this.start = start;
-            } else {
-                this.start = new Date();
+            if (interval != Calendar.SECOND && interval != Calendar.MINUTE && interval != Calendar.HOUR_OF_DAY) {
+                throw new IllegalArgumentException("invalid interval argument");
             }
-            this.sequence = 100;
-            this.subSequence = freqType;
-            this.freqType = freqType;
-            this.freqCount = freqCount;
+            if (count < 1) {
+                throw new IllegalArgumentException("invalid count argument");
+            }
+            this.startStr = start;
+            this.endStr = end;
+            this.interval = interval;
+            this.count = count;
+            String strArray[] = this.startStr.split(":");
+            if (strArray.length == 0 || strArray.length > 3) {
+                throw new IllegalArgumentException("Invalid start time argument");
+            }
+            this.startHrs = Integer.valueOf(strArray[0]);
+            this.startMins = strArray.length > 1 ? Integer.valueOf(strArray[1]) : 0;
+            this.startSecs = strArray.length > 2 ? Integer.valueOf(strArray[2]) : 0;
+            if (this.startHrs > 23 || this.startMins > 59 || this.startSecs > 59) {
+                throw new IllegalArgumentException("Invalid start time argument");
+            }
+            strArray = this.endStr.split(":");
+            if (strArray.length == 0 || strArray.length > 3) {
+                throw new IllegalArgumentException("Invalid end time argument");
+            }
+            this.endHrs = Integer.valueOf(strArray[0]);
+            this.endMins = strArray.length > 1 ? Integer.valueOf(strArray[1]) : 0;
+            this.endSecs = strArray.length > 2 ? Integer.valueOf(strArray[2]) : 0;
+            if (this.endHrs > 23 || this.endMins > 59 || this.endSecs > 59) {
+                throw new IllegalArgumentException("Invalid end time argument");
+            }
+            this.sequence = SEQUENCE_TOD_RANGE + this.startHrs;
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Created " + this, module);
             }
         }
 
+        @Override
+        public void accept(TemporalExpressionVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (obj == this) {
                 return true;
             }
             try {
-                Frequency that = (Frequency) obj;
-                return this.start.equals(that.start) && this.freqType == that.freqType && this.freqCount == that.freqCount;
-            } catch (Exception e) {}
+                TimeOfDayRange that = (TimeOfDayRange) obj;
+                return this.startStr.equals(that.startStr) && this.endStr.equals(that.endStr);
+            } catch (ClassCastException e) {}
             return false;
         }
 
-        public String toString() {
-            return super.toString() + ", start = " + this.start + ", freqType = " + this.freqType + ", freqCount = " + this.freqCount;
+        @Override
+        public Calendar first(Calendar cal) {
+            if (includesDate(cal)) {
+                return cal;
+            }
+            return next(cal);
         }
 
-        public boolean includesDate(Calendar cal) {
-            Calendar next = first(cal);
-            return next.equals(cal);
+        public int getCount() {
+            return this.count;
         }
 
-        public Calendar first(Calendar cal) {
-            Calendar first = prepareCal(cal);
-            while (first.before(cal)) {
-                first.add(this.freqType, this.freqCount);
+        public int getEndHours() {
+            return this.endHrs;
+        }
+
+        public int getEndMins() {
+            return this.endMins;
+        }
+
+        public int getEndSecs() {
+            return this.endSecs;
+        }
+
+        public int getInterval() {
+            return this.interval;
+        }
+
+        public int getStartHours() {
+            return this.startHrs;
+        }
+
+        public int getStartMins() {
+            return this.startMins;
+        }
+
+        public int getStartSecs() {
+            return this.startSecs;
+        }
+
+        @Override
+        public boolean includesDate(Calendar cal) {
+            long millis = cal.getTimeInMillis();
+            Calendar startCal = setStart(cal);
+            Calendar endCal = setEnd(startCal);
+            if (endCal.before(startCal)) {
+                endCal.add(Calendar.DAY_OF_MONTH, 1);
             }
-            return first;
+            long startMillis = startCal.getTimeInMillis();
+            long endMillis = endCal.getTimeInMillis();
+            return millis >= startMillis && millis <= endMillis;
         }
 
-        public Calendar next(Calendar cal) {
-            Calendar next = first(cal);
-            if (next.equals(cal)) {
-                next.add(this.freqType, this.freqCount);
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar next = (Calendar) cal.clone();
+            next.add(this.interval, this.count);
+            if (!includesDate(next)) {
+                Calendar last = next;
+                next = setStart(next);
+                if (next.before(last)) {
+                    next.add(Calendar.DAY_OF_MONTH, 1);
+                }
             }
             return next;
         }
 
+        protected Calendar setCalendar(Calendar cal, int hrs, int mins, int secs) {
+            Calendar newCal = (Calendar) cal.clone();
+            newCal.set(Calendar.MILLISECOND, 0);
+            newCal.set(Calendar.SECOND, secs);
+            newCal.set(Calendar.MINUTE, mins);
+            newCal.set(Calendar.HOUR_OF_DAY, hrs);
+            return newCal;
+        }
+
+        protected Calendar setEnd(Calendar cal) {
+            return setCalendar(cal, this.endHrs, this.endMins, this.endSecs);
+        }
+
+        protected Calendar setStart(Calendar cal) {
+            return setCalendar(cal, this.startHrs, this.startMins, this.startSecs);
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", start = " + this.startStr + ", end = " + this.endStr
+            + ", interval = " + this.interval + ", count = " + this.count;
+        }
+    }
+
+    /** A temporal expression that represents a mathematical union of all of its
+     * member expressions. */
+    public static class Union extends TemporalExpression {
+        protected final Set<TemporalExpression> expressionSet;
+
+        public Union(Set<TemporalExpression> expressionSet) {
+            if (expressionSet == null) {
+                throw new IllegalArgumentException("expressionSet argument cannot be null");
+            }
+            this.expressionSet = expressionSet;
+            if (containsExpression(this)) {
+                throw new IllegalArgumentException("recursive expression");
+            }
+            if (this.expressionSet.size() > 0) {
+                TemporalExpression that = this.expressionSet.iterator().next();
+                this.sequence = that.sequence;
+            }
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        @Override
         public void accept(TemporalExpressionVisitor visitor) {
             visitor.visit(this);
         }
 
-        /** Returns the start date of this expression.
-         * @return The start date of this expression
-         */
-        public Date getStartDate() {
-            return (Date) this.start.clone();
+        @Override
+        protected boolean containsExpression(TemporalExpression expression) {
+            for (TemporalExpression setItem : this.expressionSet) {
+                if (setItem.containsExpression(expression)) {
+                    return true;
+                }
+            }
+            return false;
         }
 
-        /** Returns the frequency type of this expression.
-         * @return The frequency type of this expression
-         */
-        public int getFreqType() {
-            return this.freqType;
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                return this.expressionSet.equals(((Union) obj).expressionSet);
+            } catch (ClassCastException e) {}
+            return false;
         }
 
-        /** Returns the frequency count of this expression.
-         * @return The frequency count of this expression
+        @Override
+        public Calendar first(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                Calendar first = expression.first(cal);
+                if (first != null && includesDate(first)) {
+                    return first;
+                }
+            }
+            return null;
+        }
+
+        /** Returns the member expression <code>Set</code>. The
+         * returned set is unmodifiable.
+         * @return The member expression <code>Set</code>
          */
-        public int getFreqCount() {
-            return this.freqCount;
+        public Set<TemporalExpression> getExpressionSet() {
+            return Collections.unmodifiableSet(this.expressionSet);
         }
 
-        protected Calendar prepareCal(Calendar cal) {
-            // Performs a "sane" skip forward in time - avoids time consuming loops
-            // like incrementing every second from Jan 1 2000 until today
-            Calendar skip = (Calendar) cal.clone();
-            skip.setTime(this.start);
-            long deltaMillis = cal.getTimeInMillis() - this.start.getTime();
-            if (deltaMillis < 1000) {
-                return skip;
-            }
-            long divisor = deltaMillis;
-            if (this.freqType == Calendar.DAY_OF_MONTH) {
-                divisor = 86400000;
-            } else if (this.freqType == Calendar.HOUR) {
-                divisor = 3600000;
-            } else if (this.freqType == Calendar.MINUTE) {
-                divisor = 60000;
-            } else if (this.freqType == Calendar.SECOND) {
-                divisor = 1000;
-            } else {
-                return skip;
+        @Override
+        public boolean includesDate(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                if (expression.includesDate(cal)) {
+                    return true;
+                }
             }
-            float units = deltaMillis / divisor;
-            units = (units / this.freqCount) * this.freqCount;
-            skip.add(this.freqType, (int)units);
-            while (skip.after(cal)) {
-                skip.add(this.freqType, -this.freqCount);
+            return false;
+        }
+
+        @Override
+        public Calendar next(Calendar cal, ExpressionContext context) {
+            Calendar result = null;
+            for (TemporalExpression expression : this.expressionSet) {
+                Calendar next = expression.next(cal, context);
+                if (next != null) {
+                    if (result == null || next.before(result)) {
+                        result = next;
+                    }
+                }
             }
-            return skip;
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + ", size = " + this.expressionSet.size();
         }
     }
 }

Modified: ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMacros.ftl
URL: http://svn.apache.org/viewvc/ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMacros.ftl?rev=903125&r1=903124&r2=903125&view=diff
==============================================================================
--- ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMacros.ftl (original)
+++ ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMacros.ftl Tue Jan 26 08:28:39 2010
@@ -78,6 +78,17 @@
   </tr>
 </#macro>
 
+<#macro HourOfDayRange fromHour=1 toHour=31>
+  <tr>
+    <td class="label">${uiLabelMap.CommonFrom}</td>
+    <td><@HourOfDayField fieldName="integer1" fieldValue=fromHour/></td>
+  </tr>
+  <tr>
+    <td class="label">${uiLabelMap.CommonTo}</td>
+    <td><@HourOfDayField fieldName="integer2" fieldValue=toHour/></td>
+  </tr>
+</#macro>
+
 <#macro DayOfWeekRange fromDay=firstDayOfWeek toDay=lastDayOfWeek>
   <tr>
     <td class="label">${uiLabelMap.CommonFrom}</td>
@@ -118,6 +129,17 @@
   </tr>
 </#macro>
 
+<#macro MinuteRange fromMinute=1 toMinute=31>
+  <tr>
+    <td class="label">${uiLabelMap.CommonFrom}</td>
+    <td><@MinuteField fieldName="integer1" fieldValue=fromMinute/></td>
+  </tr>
+  <tr>
+    <td class="label">${uiLabelMap.CommonTo}</td>
+    <td><@MinuteField fieldName="integer2" fieldValue=toMinute/></td>
+  </tr>
+</#macro>
+
 <#macro MonthRange fromMonth=0 toMonth=11>
   <tr>
     <td class="label">${uiLabelMap.CommonFrom}</td>

Modified: ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMaint.ftl
URL: http://svn.apache.org/viewvc/ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMaint.ftl?rev=903125&r1=903124&r2=903125&view=diff
==============================================================================
--- ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMaint.ftl (original)
+++ ofbiz/branches/release09.04/framework/webtools/webapp/webtools/tempexpr/tempExprMaint.ftl Tue Jan 26 08:28:39 2010
@@ -44,6 +44,12 @@
       <@DayOfWeekRange fromDay=temporalExpression.integer1 toDay=temporalExpression.integer2/>
     <#elseif temporalExpression.tempExprTypeId == "FREQUENCY">
       <@Frequency formName="updateExpression" fromDate=temporalExpression.date1 freqType=temporalExpression.integer1 freqValue=temporalExpression.integer2/>
+    <#elseif temporalExpression.tempExprTypeId == "DAY_OF_WEEK_RANGE">
+      <@DayOfWeekRange fromDay=temporalExpression.integer1 toDay=temporalExpression.integer2/>
+    <#elseif temporalExpression.tempExprTypeId == "HOUR_RANGE">
+      <@HourOfDayRange fromHour=temporalExpression.integer1 toHour=temporalExpression.integer2/>
+    <#elseif temporalExpression.tempExprTypeId == "MINUTE_RANGE">
+      <@MinuteRange fromMinute=temporalExpression.integer1 toMinute=temporalExpression.integer2/>
     <#elseif temporalExpression.tempExprTypeId == "MONTH_RANGE">
       <@MonthRange fromMonth=temporalExpression.integer1 toMonth=temporalExpression.integer2/>
     <#elseif temporalExpression.tempExprTypeId == "TIME_OF_DAY_RANGE">
@@ -100,6 +106,10 @@
   <hr/>
   <@CreateForm "FREQUENCY" Frequency/>
   <hr/>
+  <@CreateForm "HOUR_RANGE" HourOfDayRange/>
+  <hr/>
+  <@CreateForm "MINUTE_RANGE" MinuteRange/>
+  <hr/>
   <@CreateForm "MONTH_RANGE" MonthRange/>
   <hr/>
   <@CreateForm "TIME_OF_DAY_RANGE" TimeOfDayRange/>