My server runs on Europe/Rome timezone -and this one is the default tz on the server-, I need to schedule jobs according the user\'s timezone, so, if a user, living on Paci
You can use ZonedDateTime
from java8/java8+, In that way you will not need to explicitly convert the given time into server specific time:
protected static Trigger createCronTrigger(String triggerName, ZonedDateTime startTime, String cronExpression, int misFireInstruction, ZoneId timeZone) {
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName)
.startAt(Date.from(startTime.toInstant())).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone(timeZone)).withMisfireHandlingInstructionDoNothing())
.build();
return trigger;
}
you can read more about ZonedDateTime from Here
Date doesn't carry any TZ data, and Daylight Savings Time is actually its own TZ (EST is Easter Standard Time, EDT is Eastern Daylight Savings Time). The only thing that may pe an issue is that some places, like Phoenix Arizona, do not recognize DST. Any time you need TZ data preserved, Calendar is the way to go.
I think I found the solution, tested and it works until proved otherwise ;)
Recup My server runs on a specific timezone (i.e. Europe/Rome)
If a user on Pacific/Honolulu TZ want to schedule a job that starts on Sun, 27 Jan 2013 at 3:00PM end ends on Thu, 31 Jan 2013 at 9:00PM that fire every day every five minutes starting from 2:00PM to 10:55PM (0 0/5 14-22 * * ?) the correct way is the following:
Sample Code:
// Begin User Input
String userDefinedTZ = "Pacific/Honolulu"; // +11
int userStartYear = 2013;
int userStartMonth = Calendar.JANUARY;
int UserStartDayOfMonth = 27;
int userStartHour = 15;
int userStartMinute = 0;
int userStartSecond = 0;
int userEndYear = 2013;
int userEndMonth = Calendar.JANUARY;
int UserEndDayOfMonth = 31;
int userEndHour = 21;
int userEndMinute = 0;
int userEndSecond = 0;
// End User Input
Calendar userStartDefinedTime = Calendar.getInstance();
// set start schedule by user input
userStartDefinedTime.set(userStartYear, userStartMonth, UserStartDayOfMonth, userStartHour, userStartMinute, userStartSecond);
Calendar userEndDefinedTime = Calendar.getInstance();
// set end schedule by user input
userEndDefinedTime.set(userEndYear, userEndMonth, UserEndDayOfMonth, userEndHour, userEndMinute, userEndSecond);
CronTrigger trigger = newTrigger()
.withIdentity("name", "group")
.withSchedule(
// define timezone for the CronScheduleBuilder
cronSchedule("0 0/5 14-22 * * ?").inTimeZone(TimeZone.getTimeZone("Pacific/Honolulu"))
)
// adapt user start date to server timezone
.startAt( convertDateToServerTimeZone(userStartDefinedTime.getTime(), userDefinedTZ) )
// adapt user end date to server timezone
.endAt( convertDateToServerTimeZone(userEndDefinedTime.getTime(), userDefinedTZ) )
.build();
Utility to convert dates based on tz:
public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) {
Calendar userDefinedTime = Calendar.getInstance();
userDefinedTime.setTime(dateTime);
if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) {
System.out.println ("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone);
Calendar quartzStartDate = new GregorianCalendar(TimeZone.getTimeZone(timeZone));
quartzStartDate.set(Calendar.YEAR, userDefinedTime.get(Calendar.YEAR));
quartzStartDate.set(Calendar.MONTH, userDefinedTime.get(Calendar.MONTH));
quartzStartDate.set(Calendar.DAY_OF_MONTH, userDefinedTime.get(Calendar.DAY_OF_MONTH));
quartzStartDate.set(Calendar.HOUR_OF_DAY, userDefinedTime.get(Calendar.HOUR_OF_DAY));
quartzStartDate.set(Calendar.MINUTE, userDefinedTime.get(Calendar.MINUTE));
quartzStartDate.set(Calendar.SECOND, userDefinedTime.get(Calendar.SECOND));
quartzStartDate.set(Calendar.MILLISECOND, userDefinedTime.get(Calendar.MILLISECOND));
System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString());
return quartzStartDate;
} else {
return userDefinedTime;
}
}
Quartz Based Utility to convert dates based on tz using DateBuilder:
public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) {
Calendar userDefinedTime = Calendar.getInstance();
userDefinedTime.setTime(dateTime);
if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) {
System.out.println("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone);
Date translatedTime = DateBuilder.translateTime(userDefinedTime.getTime(), TimeZone.getDefault(), TimeZone.getTimeZone(timeZone));
Calendar quartzStartDate = new GregorianCalendar();
quartzStartDate.setTime(translatedTime);
System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString());
return quartzStartDate;
} else {
return userDefinedTime;
}
}
So on my Europe/Rome Quartz server this job are scheduled for starting from Mon Jan 28 02:00:00 CET 2013 to Fri Feb 01 08:00:00 CET 2013 and fire every five minute every day from 01:00AM to 08:55PM
When building your Dates for start and end times also specify the timezone (on the java.util.Calendar, or date format string, or org.quartz.DateBuilder) before instantiating the Date. Then quartz stores the date as milliseconds since January 1, 1970 in UTC in that particular timezone - and hence when the server's timezone changes, the trigger is not affected.