如何为 cron 触发器处理石英夏令时的用户时区?
Posted
技术标签:
【中文标题】如何为 cron 触发器处理石英夏令时的用户时区?【英文标题】:how to handle user timezone for daylight savings in quartz for cron Triggers? 【发布时间】:2018-04-16 21:08:23 【问题描述】:我的服务 api 接受石英作业的 startDate 和要执行的作业的月份日期。 在内部,我将其转换为 cron 表达式并保存在石英中。
例如,PST 中的用户今天(2017 年 11 月 3 日)提交了一个工作请求,如下所示。
"start": "2017-11-03T18:00:00-07:00",
"dayOfMonth" : 15
在这里,用户想要安排从 2017 年 11 月 3 日开始在每月 15 日下午 6 点触发的作业。所以第一天的石英将在 2017 年 11 月 15 日开火。
这就是上述请求如何转换为 cron 表达式 0 0 18 15 * ? *
的方式,这是正确的。
下面是 QRTZ_CRON_TRIGGERS 表的样子。
如您所见,time_zone_id 保存为 GMT-07:00,但在 11 月 5 日夏令时开始后,它必须为 GMT-08:00。否则我的石英工作会提前一小时启动。事实上,当我查询 nextFireTime 时,我确实得到了 1510794000000,这确实是 2017 年 11 月 15 日星期三 17:00:00(下午)在时区美国/洛杉矶(PST)
我们如何处理这个 time_zone_id 问题?
P.S:我正在使用 cronTrigger,它没有 CalendarIntervalTrigger
提供的 preserveHourOfDayAcrossDaylightSavings
的概念。
【问题讨论】:
【参考方案1】:不要使用偏移量来表示时区。相反,您可以要求用户输入时区,例如“America/Los_Angeles”。然后您可以使用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
【讨论】:
【参考方案2】:您可以使用 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;
【讨论】:
以上是关于如何为 cron 触发器处理石英夏令时的用户时区?的主要内容,如果未能解决你的问题,请参考以下文章
EBS Worker 和 SQS 的 Cron 作业和夏令时