跨时区的Java石英调度程序



我的服务器运行在欧洲/罗马时区-这是服务器上的默认时区-,我需要根据用户的时区调度作业,因此,如果用户,我住在太平洋/檀香山时区,每天晚上22:00为他所在的地区安排一个CronTrigger,我找到了这个解决方案:

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

在我的服务器上这个作业在"my"第二天的上午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();

那么工作在"太平洋/檀香山"定义的天数内正确开始/结束?

提前感谢大家的建议

我想我找到了解决方案,经过测试,它有效,直到证明不是这样;)

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

如果Pacific/Honolulu TZ的用户想要调度一个作业,从2013年1月27日星期日下午3点开始,到2013年1月31日星期四晚上9点结束,每天每5分钟从下午2点开始到10:55PM(0/5 14-22 * * ?),正确的方法如下:

  • 在CronScheduleBuilder的inTimeZone方法中设置用户时区
  • 通过将太平洋/檀香山转换为欧洲/罗马来适应服务器时间的开始和结束日期

示例代码:

// 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;
    }
}

== BEGIN OF UPDATE 2012-01-24 ==

基于石英的实用程序转换日期基于tz使用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;
    }
}

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

所以在我的欧洲/罗马石英服务器上,这个作业计划从星期一1月28日02:00:00 CET 2013开始到星期五2月01日08:00:00 CET 2013,每天从01:00AM到08:55PM每五分钟启动一次

在为开始和结束时间构建日期时,还要指定时区(在java.util. xml文件中)。日历,或日期格式字符串,或org.quartz.DateBuilder),然后实例化date。然后,quartz将日期以毫秒为单位存储在该特定时区的UTC中,自1970年1月1日起-因此,当服务器的时区更改时,触发器不受影响。

Date不携带任何时区数据,夏令时实际上是它自己的时区(EST是复活节标准时间,EDT是东部夏令时)。唯一可能造成问题的是一些地方,比如亚利桑那州的凤凰城,不承认夏时制。任何时候需要保存TZ数据,都可以使用Calendar。

您可以使用java8/java8+的ZonedDateTime,这样您就不需要显式地将给定的时间转换为服务器特定的时间:

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;
}

你可以从这里阅读更多关于ZonedDateTime

相关内容

  • 没有找到相关文章

最新更新