gt:             c.set(Calendar.HOUR_OF_DAY, c.get(Calendar.HOUR_OF_DAY) + 1);
context: /*
   * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
   * use this file except in compliance with the License. You may obtain a copy 
   * of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0 
   *   
   * Unless required by applicable law or agreed to in writing, software 
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
   * License for the specific language governing permissions and limitations 
   * under the License.
   * 
   */
  
  package org.quartz;
  
  import java.util.Calendar;
  import java.util.Date;
  import java.util.Locale;
  import java.util.TimeZone;
  
  /**
   * <code>DateBuilder</code> is used to conveniently create 
   * <code>java.util.Date</code> instances that meet particular criteria.
   *  
   * <p>Quartz provides a builder-style API for constructing scheduling-related
   * entities via a Domain-Specific Language (DSL).  The DSL can best be
   * utilized through the usage of static imports of the methods on the classes
   * <code>TriggerBuilder</code>, <code>JobBuilder</code>, 
   * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> 
   * and the various <code>ScheduleBuilder</code> implementations.</p>
   * 
   * <p>Client code can then use the DSL to write code such as this:</p>
   * <pre>
   *         JobDetail job = newJob(MyJob.class)
   *             .withIdentity("myJob")
   *             .build();
   *             
   *         Trigger trigger = newTrigger() 
   *             .withIdentity(triggerKey("myTrigger", "myTriggerGroup"))
   *             .withSchedule(simpleSchedule()
   *                 .withIntervalInHours(1)
   *                 .repeatForever())
   *             .startAt(futureDate(10, MINUTES))
   *             .build();
   *         
   *         scheduler.scheduleJob(job, trigger);
   * <pre>
   *  
   * @see TriggerBuilder
   * @see JobBuilder 
   */
  public class DateBuilder {
  
      public enum IntervalUnit { MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR };
      
      public static final int SUNDAY = 1;
  
      public static final int MONDAY = 2;
  
      public static final int TUESDAY = 3;
  
      public static final int WEDNESDAY = 4;
  
      public static final int THURSDAY = 5;
  
      public static final int FRIDAY = 6;
  
      public static final int SATURDAY = 7;
  
      public static final long MILLISECONDS_IN_MINUTE = 60l * 1000l;
  
      public static final long MILLISECONDS_IN_HOUR = 60l * 60l * 1000l;
  
      public static final long SECONDS_IN_MOST_DAYS = 24l * 60l * 60L;
  
      public static final long MILLISECONDS_IN_DAY = SECONDS_IN_MOST_DAYS * 1000l;
      
      private int month;
      private int day;
      private int year;
      private int hour;
      private int minute;
      private int second;
      private TimeZone tz;
      private Locale lc;
      
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the system default timezone.
       */
      private DateBuilder() {
          Calendar cal = Calendar.getInstance();
          
          month = cal.get(Calendar.MONTH);
          day = cal.get(Calendar.DAY_OF_MONTH);
          year = cal.get(Calendar.YEAR);
          hour = cal.get(Calendar.HOUR_OF_DAY);
          minute = cal.get(Calendar.MINUTE);
          second = cal.get(Calendar.SECOND);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given timezone.
       */
      private DateBuilder(TimeZone tz) {
          Calendar cal = Calendar.getInstance(tz);
          
          this.tz = tz;
          month = cal.get(Calendar.MONTH);
          day = cal.get(Calendar.DAY_OF_MONTH);
          year = cal.get(Calendar.YEAR);
          hour = cal.get(Calendar.HOUR_OF_DAY);
          minute = cal.get(Calendar.MINUTE);
          second = cal.get(Calendar.SECOND);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given locale.
       */
      private DateBuilder(Locale lc) {
          Calendar cal = Calendar.getInstance(lc);
          
          this.lc = lc;
          month = cal.get(Calendar.MONTH);
          day = cal.get(Calendar.DAY_OF_MONTH);
          year = cal.get(Calendar.YEAR);
          hour = cal.get(Calendar.HOUR_OF_DAY);
          minute = cal.get(Calendar.MINUTE);
          second = cal.get(Calendar.SECOND);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given timezone and locale.
       */
      private DateBuilder(TimeZone tz, Locale lc) {
          Calendar cal = Calendar.getInstance(tz, lc);
          
          this.tz = tz;
          this.lc = lc;
          month = cal.get(Calendar.MONTH);
          day = cal.get(Calendar.DAY_OF_MONTH);
          year = cal.get(Calendar.YEAR);
          hour = cal.get(Calendar.HOUR_OF_DAY);
          minute = cal.get(Calendar.MINUTE);
          second = cal.get(Calendar.SECOND);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the system default timezone.
       */
      public static DateBuilder newDate() {
          return new DateBuilder();
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given timezone.
       */
      public static DateBuilder newDateInTimezone(TimeZone tz) {
          return new DateBuilder(tz);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given locale.
       */
      public static DateBuilder newDateInLocale(Locale lc) {
          return new DateBuilder(lc);
      }
  
      /**
       * Create a DateBuilder, with initial settings for the current date and time in the given timezone and locale.
       */
      public static DateBuilder newDateInTimeZoneAndLocale(TimeZone tz, Locale lc) {
          return new DateBuilder(tz, lc);
      }
  
      /**
       * Build the Date defined by this builder instance. 
       */
      public Date build() {
          Calendar cal = null;
  
          if(tz != null && lc != null)
              cal = Calendar.getInstance(tz, lc);
          else if(tz != null)
              cal = Calendar.getInstance(tz);
          else if(lc != null)
              cal = Calendar.getInstance(lc);
          else 
            cal = Calendar.getInstance();
          
          cal.set(Calendar.YEAR, year);
          cal.set(Calendar.MONTH, month);
          cal.set(Calendar.DAY_OF_MONTH, day);
          cal.set(Calendar.HOUR_OF_DAY, hour);
          cal.set(Calendar.MINUTE, minute);
          cal.set(Calendar.SECOND, second);
          cal.set(Calendar.MILLISECOND, 0);
          
          return cal.getTime();
      }
      
      /**
       * Set the hour (0-23) for the Date that will be built by this builder.
       */
      public DateBuilder atHourOfDay(int hour) {
          validateHour(hour);
          
          this.hour = hour;
          return this;
      }
  
      /**
       * Set the minute (0-59) for the Date that will be built by this builder.
       */
      public DateBuilder atMinute(int minute) {
          validateMinute(minute);
          
          this.minute = minute;
          return this;
      }
  
      /**
       * Set the second (0-59) for the Date that will be built by this builder, and truncate the milliseconds to 000.
       */
      public DateBuilder atSecond(int second) {
          validateSecond(second);
          
          this.second = second;
          return this;
      }
  
      public DateBuilder atHourMinuteAndSecond(int hour, int minute, int second) {
          validateHour(hour);
          validateMinute(minute);
          validateSecond(second);
          
          this.hour = hour;
          this.second = second;
          this.minute = minute;
          return this;
      }
      
      /**
       * Set the day of month (1-31) for the Date that will be built by this builder.
       */
      public DateBuilder onDay(int day) {
          validateDayOfMonth(day);
          
          this.day = day;
          return this;
      }
  
      /**
       * Set the month (1-12) for the Date that will be built by this builder.
       */
      public DateBuilder inMonth(int month) {
          validateMonth(month);
          
          this.month = month;
          return this;
      }
      
      public DateBuilder inMonthOnDay(int month, int day) {
          validateMonth(month);
          validateDayOfMonth(day);
          
          this.month = month;
          this.day = day;
          return this;
      }
  
      /**
       * Set the year for the Date that will be built by this builder.
       */
      public DateBuilder inYear(int year) {
          validateYear(year);
          
          this.year = year;
          return this;
      }
  
      /**
       * Set the TimeZone for the Date that will be built by this builder (if "null", system default will be used)
       */
      public DateBuilder inTimeZone(TimeZone tz) {
          this.tz = tz;
          return this;
      }
  
      /**
       * Set the Locale for the Date that will be built by this builder (if "null", system default will be used)
       */
      public DateBuilder inLocale(Locale lc) {
          this.lc = lc;
          return this;
      }
  
      public static Date futureDate(int interval, IntervalUnit unit) {
          
          Calendar c = Calendar.getInstance();
          c.setTime(new Date());
          c.setLenient(true);
          
          c.add(translate(unit), interval);
  
          return c.getTime();
      }
      
  
      private static int translate(IntervalUnit unit) {
          switch(unit) {
              case DAY : return Calendar.DAY_OF_YEAR;
              case HOUR : return Calendar.HOUR_OF_DAY;
              case MINUTE : return Calendar.MINUTE;
              case MONTH : return Calendar.MONTH;
              case SECOND : return Calendar.SECOND;
              case MILLISECOND : return Calendar.MILLISECOND;
              case WEEK : return Calendar.WEEK_OF_YEAR;
              case YEAR : return Calendar.YEAR;
              default : throw new IllegalArgumentException("Unknown IntervalUnit");
          }
      }
  
      /**
       * <p>
       * Get a <code>Date</code> object that represents the given time, on
       * tomorrow's date.
       * </p>
       * 
       * @param second
       *          The value (0-59) to give the seconds field of the date
       * @param minute
       *          The value (0-59) to give the minutes field of the date
       * @param hour
       *          The value (0-23) to give the hours field of the date
       * @return the new date
       */
      public static Date tomorrowAt(int hour, int minute, int second) {
          validateSecond(second);
          validateMinute(minute);
          validateHour(hour);
  
          Date date = new Date();
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          // advance one day
          c.add(Calendar.DAY_OF_YEAR, 1);
          
          c.set(Calendar.HOUR_OF_DAY, hour);
          c.set(Calendar.MINUTE, minute);
          c.set(Calendar.SECOND, second);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Get a <code>Date</code> object that represents the given time, on
       * today's date (equivalent to {@link #dateOf(int, int, int)}).
       * </p>
       * 
       * @param second
       *          The value (0-59) to give the seconds field of the date
       * @param minute
       *          The value (0-59) to give the minutes field of the date
       * @param hour
       *          The value (0-23) to give the hours field of the date
       * @return the new date
       */
      public static Date todayAt(int hour, int minute, int second) {
          return dateOf(hour, minute, second);
      }
      
      /**
       * <p>
       * Get a <code>Date</code> object that represents the given time, on
       * today's date  (equivalent to {@link #todayAt(int, int, int)}).
       * </p>
       * 
       * @param second
       *          The value (0-59) to give the seconds field of the date
       * @param minute
       *          The value (0-59) to give the minutes field of the date
       * @param hour
       *          The value (0-23) to give the hours field of the date
       * @return the new date
       */
      public static Date dateOf(int hour, int minute, int second) {
          validateSecond(second);
          validateMinute(minute);
          validateHour(hour);
  
          Date date = new Date();
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          c.set(Calendar.HOUR_OF_DAY, hour);
          c.set(Calendar.MINUTE, minute);
          c.set(Calendar.SECOND, second);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Get a <code>Date</code> object that represents the given time, on the
       * given date.
       * </p>
       * 
       * @param second
       *          The value (0-59) to give the seconds field of the date
       * @param minute
       *          The value (0-59) to give the minutes field of the date
       * @param hour
       *          The value (0-23) to give the hours field of the date
       * @param dayOfMonth
       *          The value (1-31) to give the day of month field of the date
       * @param month
       *          The value (1-12) to give the month field of the date
       * @return the new date
       */
      public static Date dateOf(int hour, int minute, int second,
              int dayOfMonth, int month) {
          validateSecond(second);
          validateMinute(minute);
          validateHour(hour);
          validateDayOfMonth(dayOfMonth);
          validateMonth(month);
  
          Date date = new Date();
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
  
          c.set(Calendar.MONTH, month - 1);
          c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
          c.set(Calendar.HOUR_OF_DAY, hour);
          c.set(Calendar.MINUTE, minute);
          c.set(Calendar.SECOND, second);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Get a <code>Date</code> object that represents the given time, on the
       * given date.
       * </p>
       * 
       * @param second
       *          The value (0-59) to give the seconds field of the date
       * @param minute
       *          The value (0-59) to give the minutes field of the date
       * @param hour
       *          The value (0-23) to give the hours field of the date
       * @param dayOfMonth
       *          The value (1-31) to give the day of month field of the date
       * @param month
       *          The value (1-12) to give the month field of the date
       * @param year
       *          The value (1970-2099) to give the year field of the date
       * @return the new date
       */
      public static Date dateOf(int hour, int minute, int second,
              int dayOfMonth, int month, int year) {
          validateSecond(second);
          validateMinute(minute);
          validateHour(hour);
          validateDayOfMonth(dayOfMonth);
          validateMonth(month);
          validateYear(year);
  
          Date date = new Date();
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
  
          c.set(Calendar.YEAR, year);
          c.set(Calendar.MONTH, month - 1);
          c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
          c.set(Calendar.HOUR_OF_DAY, hour);
          c.set(Calendar.MINUTE, minute);
          c.set(Calendar.SECOND, second);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
  
      /**
       * <p>
       * Returns a date that is rounded to the next even hour after the current time.
       * </p>
       * 
       * <p>
       * For example a current time of 08:13:54 would result in a date
       * with the time of 09:00:00. If the date's time is in the 23rd hour, the
       * date's 'day' will be promoted, and the time will be set to 00:00:00.
       * </p>
       * 
       * @return the new rounded date
       */
      public static Date evenHourDateAfterNow() {
          return evenHourDate(null);
      }
      /**
       * <p>
       * Returns a date that is rounded to the next even hour above the given
       * date.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54 would result in a date
       * with the time of 09:00:00. If the date's time is in the 23rd hour, the
       * date's 'day' will be promoted, and the time will be set to 00:00:00.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenHourDate(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          c.set(Calendar.HOUR_OF_DAY, c.get(Calendar.HOUR_OF_DAY) + 1);
          c.set(Calendar.MINUTE, 0);
          c.set(Calendar.SECOND, 0);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Returns a date that is rounded to the previous even hour below the given
       * date.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54 would result in a date
       * with the time of 08:00:00.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenHourDateBefore(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
  
          c.set(Calendar.MINUTE, 0);
          c.set(Calendar.SECOND, 0);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Returns a date that is rounded to the next even minute after the current time.
       * </p>
       * 
       * <p>
       * For example a current time of 08:13:54 would result in a date
       * with the time of 08:14:00. If the date's time is in the 59th minute,
       * then the hour (and possibly the day) will be promoted.
       * </p>
       * 
       * @return the new rounded date
       */
      public static Date evenMinuteDateAfterNow() {
          return evenMinuteDate(null);
      }
      
      /**
       * <p>
       * Returns a date that is rounded to the next even minute above the given
       * date.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54 would result in a date
       * with the time of 08:14:00. If the date's time is in the 59th minute,
       * then the hour (and possibly the day) will be promoted.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenMinuteDate(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1);
          c.set(Calendar.SECOND, 0);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Returns a date that is rounded to the previous even minute below the 
       * given date.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54 would result in a date
       * with the time of 08:13:00.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenMinuteDateBefore(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
  
          c.set(Calendar.SECOND, 0);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Returns a date that is rounded to the next even second after the current time.
       * </p>
       * 
       * @return the new rounded date
       */
      public static Date evenSecondDateAfterNow() {
          return evenSecondDate(null);
      }
      /**
       * <p>
       * Returns a date that is rounded to the next even second above the given
       * date.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenSecondDate(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          c.set(Calendar.SECOND, c.get(Calendar.SECOND) + 1);
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
  
      /**
       * <p>
       * Returns a date that is rounded to the previous even second below the
       * given date.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54.341 would result in a
       * date with the time of 08:13:00.000.
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @return the new rounded date
       */
      public static Date evenSecondDateBefore(Date date) {
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
  
          c.set(Calendar.MILLISECOND, 0);
  
          return c.getTime();
      }
      
      /**
       * <p>
       * Returns a date that is rounded to the next even multiple of the given
       * minute.
       * </p>
       * 
       * <p>
       * For example an input date with a time of 08:13:54, and an input
       * minute-base of 5 would result in a date with the time of 08:15:00. The
       * same input date with an input minute-base of 10 would result in a date
       * with the time of 08:20:00. But a date with the time 08:53:31 and an
       * input minute-base of 45 would result in 09:00:00, because the even-hour
       * is the next 'base' for 45-minute intervals.
       * </p>
       * 
       * <p>
       * More examples: <table>
       * <tr>
       * <th>Input Time</th>
       * <th>Minute-Base</th>
       * <th>Result Time</th>
       * </tr>
       * <tr>
       * <td>11:16:41</td>
       * <td>20</td>
       * <td>11:20:00</td>
       * </tr>
       * <tr>
       * <td>11:36:41</td>
       * <td>20</td>
       * <td>11:40:00</td>
       * </tr>
       * <tr>
       * <td>11:46:41</td>
       * <td>20</td>
       * <td>12:00:00</td>
       * </tr>
       * <tr>
       * <td>11:26:41</td>
       * <td>30</td>
       * <td>11:30:00</td>
       * </tr>
       * <tr>
       * <td>11:36:41</td>
       * <td>30</td>
       * <td>12:00:00</td>
       * </tr>
       * <td>11:16:41</td>
       * <td>17</td>
       * <td>11:17:00</td>
       * </tr>
       * </tr>
       * <td>11:17:41</td>
       * <td>17</td>
       * <td>11:34:00</td>
       * </tr>
       * </tr>
       * <td>11:52:41</td>
       * <td>17</td>
       * <td>12:00:00</td>
       * </tr>
       * </tr>
       * <td>11:52:41</td>
       * <td>5</td>
       * <td>11:55:00</td>
       * </tr>
       * </tr>
       * <td>11:57:41</td>
       * <td>5</td>
       * <td>12:00:00</td>
       * </tr>
       * </tr>
       * <td>11:17:41</td>
       * <td>0</td>
       * <td>12:00:00</td>
       * </tr>
       * </tr>
       * <td>11:17:41</td>
       * <td>1</td>
       * <td>11:08:00</td>
       * </tr>
       * </table>
       * </p>
       * 
       * @param date
       *          the Date to round, if <code>null</code> the current time will
       *          be used
       * @param minuteBase
       *          the base-minute to set the time on
       * @return the new rounded date
       * 
       * @see #nextGivenSecondDate(Date, int)
       */
      public static Date nextGivenMinuteDate(Date date, int minuteBase) {
          if (minuteBase < 0 || minuteBase > 59) {
              throw new IllegalArgumentException(
                      "minuteBase must be >=0 and <= 59");
          }
  
          if (date == null) {
              date = new Date();
          }
  
          Calendar c = Calendar.getInstance();
          c.setTime(date);
          c.setLenient(true);
  
          if (minuteBase == 0) {
  