如何处理用于cron触发器的石英夏令时的用户时区?

时间:2017-11-04 04:57:24

标签: quartz-scheduler dst quartz crontrigger

我的服务api接受石英作业的startDate和执行作业的日期。 在内部,我将其转换为cron表达式并保存在quartz中。

例如,PST中的用户今天(2017年11月3日)提交了一份工作请求,如下所示。

{
"start": "2017-11-03T18:00:00-07:00",
"dayOfMonth" : 15
}

此处,用户希望安排在2017-11-03开始的每月15日下午6点开始的工作。因此第一天石英将于2017-11-15开火。 这就是上述请求转换为cron表达式0 0 18 15 * ? *的方式,这是正确的。 以下是QRTZ_CRON_TRIGGERS表的样子。

enter image description here

如您所知,time_zone_id保存为格林威治标准时间-07:00,但一旦11月5日夏令时启动,则必须是格林威治标准时间-08:00。或者我的石英工作会提前一小时开火。事实上,当我查询 nextFireTime 时,我确实得到了1510794000000,这确实是 2017年11月15日星期三17:00:00(pm)在时区America / Los Angeles(PST)< /强>

我们如何处理这个time_zone_id问题?

P.S:我使用的是cronTrigger,它没有preserveHourOfDayAcrossDaylightSavings提供的CalendarIntervalTrigger概念。

2 个答案:

答案 0 :(得分:1)

不要使用偏移来表示时区。相反,您可以要求用户传入时区,例如&#34; America / Los_Angeles &#34;。然后,您可以使用http://www.quartz-scheduler.org/api/2.2.1/org/quartz/CronScheduleBuilder.html#inTimeZone(java.util.TimeZone)以适当的时区创建触发器。

inTimeZone(TimeZone.getTimeZone("USER_ENTERED_VALUE")

最后,当您查看QRTZ_CRON_TRIGGERS表时,TIME_ZONE_ID的值将为 America / Los_Angeles

答案 1 :(得分:0)

您可以使用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;
}