跨TimeZone的Java Quartz-Scheduler

我的服务器在欧洲/罗马时区运行 – 这个是服务器上的默认tz,我需要根据用户的时区安排工作,因此,如果居住在Pacific / Honolulu时区的用户安排一个CronTrigger,每个人都会触发我发现这个解决方案的一天是晚上22点为他的地球区域:

CronTrigger trigger = newTrigger() .withIdentity("name", "group") .withSchedule( cronSchedule("0 0 22 ? * *").inTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")) ) .startNow() .build(); 

在我的服务器上,这项工作从第二天“我的”上午09:00开始

除了保持更新时区(即时区更新工具 )之外,还有一些特殊问题需要考虑吗?

如果我想为上一个作业定义.startAt()和.endAt(),这种日期是否正常? 使用此程序可以安全地使用夏令时吗?

 Calendar calTZStarts = new GregorianCalendar(TimeZone.getTimeZone("Pacific/Honolulu")); calTZStarts.set(2013, Calendar.JANUARY, 10); Calendar calTZEnds = new GregorianCalendar(TimeZone.getTimeZone("Pacific/Honolulu")); calTZEnds.set(2013, Calendar.JANUARY, 30); Calendar calStarts = Calendar.getInstance(); calStarts.set(Calendar.YEAR, calTZStarts.get(Calendar.YEAR)); calStarts.set(Calendar.MONTH, calTZStarts.get(Calendar.MONTH)); calStarts.set(Calendar.DAY_OF_MONTH, calTZStarts.get(Calendar.DAY_OF_MONTH)); calStarts.set(Calendar.HOUR_OF_DAY, calTZStarts.get(Calendar.HOUR_OF_DAY)); calStarts.set(Calendar.MINUTE, calTZStarts.get(Calendar.MINUTE)); calStarts.set(Calendar.SECOND, calTZStarts.get(Calendar.SECOND)); calStarts.set(Calendar.MILLISECOND, calTZStarts.get(Calendar.MILLISECOND)); Calendar calEnds = Calendar.getInstance(); calEnds.set(Calendar.YEAR, calTZEnds.get(Calendar.YEAR)); calEnds.set(Calendar.MONTH, calTZEnds.get(Calendar.MONTH)); calEnds.set(Calendar.DAY_OF_MONTH, calTZEnds.get(Calendar.DAY_OF_MONTH)); calEnds.set(Calendar.HOUR_OF_DAY, calTZEnds.get(Calendar.HOUR_OF_DAY)); calEnds.set(Calendar.MINUTE, calTZEnds.get(Calendar.MINUTE)); calEnds.set(Calendar.SECOND, calTZEnds.get(Calendar.SECOND)); calEnds.set(Calendar.MILLISECOND, calTZEnds.get(Calendar.MILLISECOND)); CronTrigger trigger = newTrigger() .withIdentity("name", "group") .withSchedule( cronSchedule("0 0 22 ? * *").inTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")) ) .startAt(calStarts.getTime()) .endAt(calEnds.getTime()) .build(); 

或者我必须设置简单的开始和结束使用:

 Calendar calTZStarts = new GregorianCalendar(); calTZStarts.set(2013, Calendar.JANUARY, 10, 0, 0, 0); Calendar calTZEnds = new GregorianCalendar(); calTZEnds.set(2013, Calendar.JANUARY, 30, 0, 0, 0); CronTrigger trigger = newTrigger() .withIdentity("name", "group") .withSchedule( cronSchedule("0 0 22 ? * *").inTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")) ) .startAt(calTZStarts.getTime()) .endAt(calTZEnds.getTime()) .build(); 

然后,工作在“太平洋/檀香山”定义的日子里正确开始/结束?

提前感谢您的每一个建议

我想我找到了解决方案,经过测试,直到certificate不是这样;)

Recup我的服务器在特定时区(即欧洲/罗马)运行

如果太平洋/檀香山TZ上的用户想要安排在Sun开始的工作,2013年1月27日下午3:00结束于2013年1月31日星期四晚上9点,每天从下午2:00开始,每隔五分钟开始一次10:55 PM(0 0/5 14-22 * *?)正确的方法如下:

  • 在CronScheduleBuilder上的inTimeZone方法中设置用户时区
  • 通过从Pacific / Honolulu转换到Europe / Rome,适应服务器时间startAt和endAt日期

示例代码:

 // 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(); 

用于根据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; } } 

==开始更新2012-01-24 ==

Quartz Based Utility使用DateBuilder基于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); 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; } } 

== END OF UPDATE 2012-01-24 ==

所以在我的欧洲/罗马Quartz服务器上,这份工作计划从2013年1月28日02:00:00 CET到2013年2月1日星期五08:00:00 CET开始,每天从凌晨01:00到08每隔5分钟开火: 55PM

在为开始和结束时间构建日期时,还要在实例化Date之前指定时区(在java.util.Calendar或日期格式字符串或org.quartz.DateBuilder上)。 然后,quartz将该日期存储为1970年1月1日以来在该特定时区的UTC时间内的毫秒数 – 因此当服务器的时区发生变化时,触发器不会受到影响。

日期不携带任何TZ数据,夏令时实际上是它自己的TZ(EST是复活节标准时间,EDT是东部夏令时)。 唯一可能出现问题的是像亚利桑那州凤凰城这样的地方不承认夏令时。 任何时候你需要保留TZ数据,日历是要走的路。