跨时区的Java石英调度(Java Quartz-Scheduler across TimeZone

2019-07-18 03:07发布

我的服务器上的欧洲/罗马时区 - 和运行这个人是在服务器 - 默认TZ,我需要安排根据用户的时区工作,所以,如果一个用户,居住在太平洋/火奴鲁鲁时区,时间安排一个触发间隔一CronTrigger每天晚上22:00为他的区域地球,我发现这个解决方案:

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

然后在作业开始/结束正确“太平洋/火奴鲁鲁”中定义天?

在此先感谢每一个建议

Answer 1:

我想我找到了解决方案,测试,它的工作原理,直到证明并非如此;)

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

如果太平洋/火奴鲁鲁TZ用户要计划,在下午3:00于星期四结束时止,2013年1月31日于星期日,2013年1月27日开始于9:00 PM那火每天每五分钟开始,从下午2:00到作业下午10:55(?0 0/5 14-22 *。*)的正确方法如下:

  • 设置在inTimeZone方法的用户时区上CronScheduleBuilder
  • 通过转换太平洋/火奴鲁鲁欧洲/罗马适应服务器时间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;
    }
}

== UPDATE 2012-01-24作者BEGIN ==

石英基于效用转换基于使用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;
    }
}

== UPDATE 2012-01-24年末==

所以, 我的欧洲/罗马石英服务器上的这项工作计划于周一从开始1月28日02:00:00 CET 2013年至周五年2月1 08:00:00 CET 2013年和每天每消防5分钟从上午01:00到08: 55PM

当构建日期的开始和结束时间实例的日期之前,还可以指定时区(在java.util.Calendar中,或日期格式字符串,或org.quartz.DateBuilder)。 然后石英存储自1970年1月1日,在UTC在特定时区的时间为毫秒 - 因此当服务器的时区的变化,触发不受影响。



Answer 2:

日期不携带任何TZ的数据,夏令时其实是自己的TZ(EST是复活节标准时间,EDT是东部夏令时)。 可PE问题的唯一的事情就是有些地方,像亚利桑那州凤凰城,不承认DST。 你需要TZ数据保留任何时候,日历是要走的路。



文章来源: Java Quartz-Scheduler across TimeZone