org.quartz.CronTrigger Maven / Gradle / Ivy
/*
* Copyright 2004-2005 OpenSymphony
*
* 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.
*
*/
/*
* Previously Copyright (c) 2001-2004 James House
*/
package org.quartz;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/**
*
* A concrete {@link Trigger}
that is used to fire a {@link org.quartz.JobDetail}
* at given moments in time, defined with Unix 'cron-like' definitions.
*
*
*
* For those unfamiliar with "cron", this means being able to create a firing
* schedule such as: "At 8:00am every Monday through Friday" or "At 1:30am
* every last Friday of the month".
*
*
*
* The format of a "Cron-Expression" string is documented on the
* {@link org.quartz.CronExpression} class.
*
*
*
* Here are some full examples:
*
* Expression
*
* Meaning
*
*
* "0 0 12 * * ?"
*
* Fire at 12pm (noon) every day
*
*
* "0 15 10 ? * *"
*
* Fire at 10:15am every day
*
*
* "0 15 10 * * ?"
*
* Fire at 10:15am every day
*
*
* "0 15 10 * * ? *"
*
* Fire at 10:15am every day
*
*
* "0 15 10 * * ? 2005"
*
* Fire at 10:15am every day during the year 2005
*
*
*
* "0 * 14 * * ?"
*
* Fire every minute starting at 2pm and ending at 2:59pm, every day
*
*
*
* "0 0/5 14 * * ?"
*
* Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day
*
*
*
* "0 0/5 14,18 * * ?"
*
* Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day
*
*
*
* "0 0-5 14 * * ?"
*
* Fire every minute starting at 2pm and ending at 2:05pm, every day
*
*
*
* "0 10,44 14 ? 3 WED"
*
* Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.
*
*
*
* "0 15 10 ? * MON-FRI"
*
* Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
*
*
*
* "0 15 10 15 * ?"
*
* Fire at 10:15am on the 15th day of every month
*
*
*
* "0 15 10 L * ?"
*
* Fire at 10:15am on the last day of every month
*
*
*
* "0 15 10 ? * 6L"
*
* Fire at 10:15am on the last Friday of every month
*
*
*
* "0 15 10 ? * 6L"
*
* Fire at 10:15am on the last Friday of every month
*
*
*
* "0 15 10 ? * 6L 2002-2005"
*
* Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005
*
*
*
* "0 15 10 ? * 6#3"
*
* Fire at 10:15am on the third Friday of every month
*
*
*
*
*
*
* Pay attention to the effects of '?' and '*' in the day-of-week and
* day-of-month fields!
*
*
*
* NOTES:
*
* - Support for specifying both a day-of-week and a day-of-month value is
* not complete (you'll need to use the '?' character in on of these fields).
*
* - Be careful when setting fire times between mid-night and 1:00 AM -
* "daylight savings" can cause a skip or a repeat depending on whether the
* time moves back or jumps forward.
*
*
*
* @see Trigger
* @see SimpleTrigger
* @see TriggerUtils
*
* @author Sharada Jambula, James House
* @author Contributions from Mads Henderson
*/
public class CronTrigger extends Trigger {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Constants.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
*
* Instructs the {@link Scheduler}
that upon a mis-fire
* situation, the {@link CronTrigger}
wants to be fired now
* by Scheduler
.
*
*/
public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
/**
*
* Instructs the {@link Scheduler}
that upon a mis-fire
* situation, the {@link CronTrigger}
wants to have it's
* next-fire-time updated to the next time in the schedule after the
* current time (taking into account any associated {@link Calendar}
,
* but it does not want to be fired now.
*
*/
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Data members.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
private CronExpression cronEx = null;
private Date startTime = null;
private Date endTime = null;
private Date nextFireTime = null;
private Date previousFireTime = null;
private transient TimeZone timeZone = null;
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Constructors.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
*
* Create a CronTrigger
with no settings.
*
*
*
* The start-time will also be set to the current time, and the time zone
* will be set the the system's default time zone.
*
*/
public CronTrigger() {
super();
setStartTime(new Date());
setTimeZone(TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with the given name and group.
*
*
*
* The start-time will also be set to the current time, and the time zone
* will be set the the system's default time zone.
*
*/
public CronTrigger(String name, String group) {
super(name, group);
setStartTime(new Date());
setTimeZone(TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with the given name, group and
* expression.
*
*
*
* The start-time will also be set to the current time, and the time zone
* will be set the the system's default time zone.
*
*/
public CronTrigger(String name, String group, String cronExpression)
throws ParseException {
super(name, group);
setCronExpression(cronExpression);
setStartTime(new Date());
setTimeZone(TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with the given name and group, and
* associated with the identified {@link org.quartz.JobDetail}
.
*
*
*
* The start-time will also be set to the current time, and the time zone
* will be set the the system's default time zone.
*
*/
public CronTrigger(String name, String group, String jobName,
String jobGroup) {
super(name, group, jobName, jobGroup);
setStartTime(new Date());
setTimeZone(TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with the given name and group,
* associated with the identified {@link org.quartz.JobDetail}
,
* and with the given "cron" expression.
*
*
*
* The start-time will also be set to the current time, and the time zone
* will be set the the system's default time zone.
*
*/
public CronTrigger(String name, String group, String jobName,
String jobGroup, String cronExpression) throws ParseException {
this(name, group, jobName, jobGroup, null, null, cronExpression,
TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with the given name and group,
* associated with the identified {@link org.quartz.JobDetail}
,
* and with the given "cron" expression resolved with respect to the TimeZone
.
*
*/
public CronTrigger(String name, String group, String jobName,
String jobGroup, String cronExpression, TimeZone timeZone)
throws ParseException {
this(name, group, jobName, jobGroup, null, null, cronExpression,
timeZone);
}
/**
*
* Create a CronTrigger
that will occur at the given time,
* until the given end time.
*
*
*
* If null, the start-time will also be set to the current time, the time
* zone will be set the the system's default.
*
*
* @param startTime
* A Date
set to the time for the Trigger
* to fire.
* @param endTime
* A Date
set to the time for the Trigger
* to quit repeat firing.
*/
public CronTrigger(String name, String group, String jobName,
String jobGroup, Date startTime, Date endTime, String cronExpression)
throws ParseException {
super(name, group, jobName, jobGroup);
setCronExpression(cronExpression);
if (startTime == null) startTime = new Date();
setStartTime(startTime);
if (endTime != null) setEndTime(endTime);
setTimeZone(TimeZone.getDefault());
}
/**
*
* Create a CronTrigger
with fire time dictated by the
* cronExpression
resolved with respect to the specified
* timeZone
occuring from the startTime
until
* the given endTime
.
*
*
*
* If null, the start-time will also be set to the current time. If null,
* the time zone will be set to the system's default.
*
*
* @param name
* of the Trigger
* @param group
* of the Trigger
* @param jobName,
* name of the {@link org.quartz.JobDetail}
* executed on firetime
* @param jobGroup,
* group of the {@link org.quartz.JobDetail}
* executed on firetime
* @param startTime
* A Date
set to the earliest time for the Trigger
* to start firing.
* @param endTime
* A Date
set to the time for the Trigger
* to quit repeat firing.
* @param cronExpression,
* A cron expression dictating the firing sequence of the Trigger
* @param timeZone,
* Specifies for which time zone the cronExpression
* should be interprted, i.e. the expression 0 0 10 * * ?, is
* resolved to 10:00 am in this time zone.
* @throws ParseException
* if the cronExpression
is invalid.
*/
public CronTrigger(String name, String group, String jobName,
String jobGroup, Date startTime, Date endTime,
String cronExpression, TimeZone timeZone) throws ParseException {
super(name, group, jobName, jobGroup);
setCronExpression(cronExpression);
if (startTime == null) startTime = new Date();
setStartTime(startTime);
if (endTime != null) setEndTime(endTime);
if (timeZone == null) {
setTimeZone(TimeZone.getDefault());
} else {
setTimeZone(timeZone);
}
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
public Object clone() {
CronTrigger copy = (CronTrigger) super.clone();
copy.setCronExpression((CronExpression)cronEx.clone());
return copy;
}
public void setCronExpression(String cronExpression) throws ParseException {
this.cronEx = new CronExpression(cronExpression);
this.cronEx.setTimeZone(getTimeZone());
}
public String getCronExpression() {
return cronEx == null ? null : cronEx.getCronExpression();
}
public void setCronExpression(CronExpression cronExpression) {
this.cronEx = cronExpression;
this.timeZone = cronExpression.getTimeZone();
}
/**
*
* Get the time at which the CronTrigger
should occur.
*
*/
public Date getStartTime() {
return this.startTime;
}
public void setStartTime(Date startTime) {
if (startTime == null)
throw new IllegalArgumentException("Start time cannot be null");
Date eTime = getEndTime();
if (eTime != null && startTime != null && eTime.before(startTime))
throw new IllegalArgumentException(
"End time cannot be before start time");
// round off millisecond...
// Note timeZone is not needed here as parameter for
// Calendar.getInstance(),
// since time zone is implicit when using a Date in the setTime method.
Calendar cl = Calendar.getInstance();
cl.setTime(startTime);
cl.set(Calendar.MILLISECOND, 0);
this.startTime = cl.getTime();
}
/**
*
* Get the time at which the CronTrigger
should quit
* repeating - even if repeastCount isn't yet satisfied.
*
*
* @see #getFinalFireTime()
*/
public Date getEndTime() {
return this.endTime;
}
public void setEndTime(Date endTime) {
Date sTime = getStartTime();
if (sTime != null && endTime != null && sTime.after(endTime))
throw new IllegalArgumentException(
"End time cannot be before start time");
this.endTime = endTime;
}
/**
*
* Returns the next time at which the CronTrigger
will fire.
* If the trigger will not fire again, null
will be
* returned. The value returned is not guaranteed to be valid until after
* the Trigger
has been added to the scheduler.
*
*/
public Date getNextFireTime() {
return this.nextFireTime;
}
/**
*
* Returns the previous time at which the CronTrigger
will
* fire. If the trigger has not yet fired, null
will be
* returned.
*/
public Date getPreviousFireTime() {
return this.previousFireTime;
}
/**
*
* Sets the next time at which the CronTrigger
will fire.
* This method should not be invoked by client code.
*
*/
public void setNextFireTime(Date nextFireTime) {
this.nextFireTime = nextFireTime;
}
/**
*
* Set the previous time at which the SimpleTrigger
fired.
*
*
*
* This method should not be invoked by client code.
*
*/
public void setPreviousFireTime(Date previousFireTime) {
this.previousFireTime = previousFireTime;
}
/**
*
* Returns the time zone for which the cronExpression
of
* this CronTrigger
will be resolved.
*
*/
public TimeZone getTimeZone() {
if(cronEx != null) return cronEx.getTimeZone();
if (timeZone == null) timeZone = TimeZone.getDefault();
return timeZone;
}
/**
*
* Sets the time zone for which the cronExpression
of this
* CronTrigger
will be resolved.
*
*/
public void setTimeZone(TimeZone timeZone) {
if(cronEx != null) cronEx.setTimeZone(timeZone);
this.timeZone = timeZone;
}
/**
*
* Returns the next time at which the CronTrigger
will fire,
* after the given time. If the trigger will not fire after the given time,
* null
will be returned.
*
*
*
* Note that the date returned is NOT validated against the related
* org.quartz.Calendar (if any)
*
*/
public Date getFireTimeAfter(Date afterTime) {
if (afterTime == null) afterTime = new Date();
if (startTime.after(afterTime))
afterTime = new Date(startTime.getTime() - 1000l);
Date pot = getTimeAfter(afterTime);
if (endTime != null && pot != null && pot.after(endTime)) return null;
return pot;
}
/**
*
* Returns the final time at which the CronTrigger
will
* fire.
*
*
*
* Note that the return time *may* be in the past. and the date returned is
* not validated against org.quartz.calendar
*
*/
public Date getFinalFireTime() {
if (this.endTime != null) return getTimeBefore(this.endTime);
else
return null;
}
/**
*
* Determines whether or not the CronTrigger
will occur
* again.
*
*/
public boolean mayFireAgain() {
return (getNextFireTime() != null);
}
protected boolean validateMisfireInstruction(int misfireInstruction) {
if (misfireInstruction < MISFIRE_INSTRUCTION_SMART_POLICY)
return false;
if (misfireInstruction > MISFIRE_INSTRUCTION_DO_NOTHING) return false;
return true;
}
/**
*
* Updates the CronTrigger
's state based on the
* MISFIRE_INSTRUCTION_XXX that was selected when the SimpleTrigger
* was created.
*
*
*
* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
* then the following scheme will be used:
*
* - The instruction will be interpreted as
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
*
*
*/
public void updateAfterMisfire(org.quartz.Calendar cal) {
int instr = getMisfireInstruction();
if (instr == MISFIRE_INSTRUCTION_SMART_POLICY)
instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;
if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {
Date newFireTime = getFireTimeAfter(new Date());
while (newFireTime != null && cal != null
&& !cal.isTimeIncluded(newFireTime.getTime())) {
newFireTime = getFireTimeAfter(newFireTime);
}
setNextFireTime(newFireTime);
} else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
setNextFireTime(new Date());
}
}
/**
*
* Determines whether the date and (optionally) time of the given Calendar
* instance falls on a scheduled fire-time of this trigger.
*
*
*
* Equivalent to calling willFireOn(cal, false)
.
*
*
* @param test the date to compare
*
* @see #willFireOn(Calendar, boolean)
*/
public boolean willFireOn(Calendar test) {
return willFireOn(test, false);
}
/**
*
* Determines whether the date and (optionally) time of the given Calendar
* instance falls on a scheduled fire-time of this trigger.
*
*
*
* Note that the value returned is NOT validated against the related
* org.quartz.Calendar (if any)
*
*
* @param test the date to compare
* @param dayOnly if set to true, the method will only determine if the
* trigger will fire during the day represented by the given Calendar
* (hours, minutes and seconds will be ignored).
* @see #willFireOn(Calendar)
*/
public boolean willFireOn(Calendar test, boolean dayOnly) {
test = (Calendar) test.clone();
test.set(Calendar.MILLISECOND, 0); // don't compare millis.
if(dayOnly) {
test.set(Calendar.HOUR, 0);
test.set(Calendar.MINUTE, 0);
test.set(Calendar.SECOND, 0);
}
Date testTime = test.getTime();
Date fta = getFireTimeAfter(new Date(test.getTime().getTime() - 1000));
Calendar p = Calendar.getInstance(test.getTimeZone());
p.setTime(fta);
int year = p.get(Calendar.YEAR);
int month = p.get(Calendar.MONTH);
int day = p.get(Calendar.DATE);
if(dayOnly) {
return (year == test.get(Calendar.YEAR)
&& month == test.get(Calendar.MONTH)
&& day == test.get(Calendar.DATE));
}
while(fta.before(testTime)) {
fta = getFireTimeAfter(fta);
}
if(fta.equals(testTime))
return true;
return false;
}
/**
*
* Called after the {@link Scheduler}
has executed the
* {@link org.quartz.JobDetail}
associated with the Trigger
* in order to get the final instruction code from the trigger.
*
*
* @param context
* is the JobExecutionContext
that was used by the
* Job
'sexecute(xx)
method.
* @param result
* is the JobExecutionException
thrown by the
* Job
, if any (may be null).
* @return one of the Trigger.INSTRUCTION_XXX constants.
*
* @see #INSTRUCTION_NOOP
* @see #INSTRUCTION_RE_EXECUTE_JOB
* @see #INSTRUCTION_DELETE_TRIGGER
* @see #INSTRUCTION_SET_TRIGGER_COMPLETE
* @see #triggered(Calendar)
*/
public int executionComplete(JobExecutionContext context,
JobExecutionException result) {
if (result != null && result.refireImmediately())
return INSTRUCTION_RE_EXECUTE_JOB;
if (result != null && result.unscheduleFiringTrigger())
return INSTRUCTION_SET_TRIGGER_COMPLETE;
if (result != null && result.unscheduleAllTriggers())
return INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE;
if (!mayFireAgain()) return INSTRUCTION_DELETE_TRIGGER;
return INSTRUCTION_NOOP;
}
/**
*
* Called when the {@link Scheduler}
has decided to 'fire'
* the trigger (execute the associated Job
), in order to
* give the Trigger
a chance to update itself for its next
* triggering (if any).
*
*
* @see #executionComplete(JobExecutionContext, JobExecutionException)
*/
public void triggered(org.quartz.Calendar calendar) {
previousFireTime = nextFireTime;
nextFireTime = getFireTimeAfter(nextFireTime);
while (nextFireTime != null && calendar != null
&& !calendar.isTimeIncluded(nextFireTime.getTime())) {
nextFireTime = getFireTimeAfter(nextFireTime);
}
}
/**
*
* @see org.quartz.Trigger#updateWithNewCalendar(org.quartz.Calendar, long)
*/
public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold)
{
nextFireTime = getFireTimeAfter(previousFireTime);
Date now = new Date();
do {
while (nextFireTime != null && calendar != null
&& !calendar.isTimeIncluded(nextFireTime.getTime())) {
nextFireTime = getFireTimeAfter(nextFireTime);
}
if(nextFireTime != null && nextFireTime.before(now)) {
long diff = now.getTime() - nextFireTime.getTime();
if(diff >= misfireThreshold) {
nextFireTime = getFireTimeAfter(nextFireTime);
continue;
}
}
}while(false);
}
/**
*
* Called by the scheduler at the time a Trigger
is first
* added to the scheduler, in order to have the Trigger
* compute its first fire time, based on any associated calendar.
*
*
*
* After this method has been called, getNextFireTime()
* should return a valid answer.
*
*
* @return the first time at which the Trigger
will be fired
* by the scheduler, which is also the same value getNextFireTime()
* will return (until after the first firing of the Trigger
).
*
*/
public Date computeFirstFireTime(org.quartz.Calendar calendar) {
nextFireTime = getFireTimeAfter(new Date(startTime.getTime() - 1000l));
while (nextFireTime != null && calendar != null
&& !calendar.isTimeIncluded(nextFireTime.getTime())) {
nextFireTime = getFireTimeAfter(nextFireTime);
}
return nextFireTime;
}
public String getExpressionSummary() {
return cronEx == null ? null : cronEx.getExpressionSummary();
}
////////////////////////////////////////////////////////////////////////////
//
// Computation Functions
//
////////////////////////////////////////////////////////////////////////////
protected Date getTimeAfter(Date afterTime) {
return cronEx.getTimeAfter(afterTime);
}
protected Date getTimeBefore(Date endTime)
{
return null;
}
public static void main(String[] args) // TODO: remove method after good
// unit testing
throws Exception {
String expr = "15 10 0/4 * * ?";
if(args != null && args.length > 0 && args[0] != null)
expr = args[0];
CronTrigger ct = new CronTrigger("t", "g", "j", "g", new Date(), null, expr);
ct.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.err.println(ct.getExpressionSummary());
System.err.println("tz=" + ct.getTimeZone().getID());
System.err.println();
java.util.List times = TriggerUtils.computeFireTimes(ct, null, 25);
for (int i = 0; i < times.size(); i++) {
System.err.println("firetime = " + times.get(i));
}
Calendar tt = Calendar.getInstance();
tt.set(Calendar.DATE, 17);
tt.set(Calendar.MONTH, 5 - 1);
tt.set(Calendar.HOUR, 11);
tt.set(Calendar.MINUTE, 0);
tt.set(Calendar.SECOND, 7);
System.err.println("\nWill fire on: " + tt.getTime() + " -- " + ct.willFireOn(tt, false));
// CRON Expression: 0 0 9 * * ?
//
// TimeZone.getDefault().getDisplayName() = Central African Time
// TimeZone.getDefault().getID() = Africa/Harare
//
//// System.err.println();
//// System.err.println();
//// System.err.println();
//// System.err.println("Daylight test:");
////
//// CronTrigger trigger = new CronTrigger();
////
//// TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
//// // TimeZone timeZone = TimeZone.getDefault();
////
//// trigger.setTimeZone(timeZone);
//// trigger.setCronExpression("0 0 1 ? 4 *");
////
//// Date start = new Date(1056319200000L);
//// Date end = new Date(1087682399000L);
////
//// trigger.setStartTime(start);
//// trigger.setEndTime(end);
////
//// Date next = new Date(1056232800000L);
//// while (next != null) {
//// next = trigger.getFireTimeAfter(next);
//// if (next != null) {
//// Calendar cal = Calendar.getInstance();
//// cal.setTimeZone(timeZone);
//// cal.setTime(next);
//// System.err.println(cal.get(Calendar.MONTH) + "/"
//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR)
//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":"
//// + cal.get(Calendar.MINUTE));
//// }
//// }
////
//// System.err.println();
//// System.err.println();
//// System.err.println();
//// System.err.println("Midnight test:");
////
//// trigger = new CronTrigger();
////
//// timeZone = TimeZone.getTimeZone("Asia/Jerusalem");
//// // timeZone = TimeZone.getTimeZone("America/Los_Angeles");
//// // TimeZone timeZone = TimeZone.getDefault();
////
//// trigger.setTimeZone(timeZone);
//// trigger.setCronExpression("0 /15 * ? 4 *");
////
//// start = new Date(1056319200000L);
//// end = new Date(1087682399000L);
////
//// trigger.setStartTime(start);
//// trigger.setEndTime(end);
////
//// next = new Date(1056232800000L);
//// while (next != null) {
//// next = trigger.getFireTimeAfter(next);
//// if (next != null) {
//// Calendar cal = Calendar.getInstance();
//// cal.setTimeZone(timeZone);
//// cal.setTime(next);
//// System.err.println(cal.get(Calendar.MONTH) + "/"
//// + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR)
//// + " - " + cal.get(Calendar.HOUR_OF_DAY) + ":"
//// + cal.get(Calendar.MINUTE));
//// }
//// }
}
}