利用石英Cron触发器处理夏令时的方法
我有一个石英cron触发器,看起来是这样的:利用石英Cron触发器处理夏令时的方法,cron,quartz-scheduler,dst,Cron,Quartz Scheduler,Dst,我有一个石英cron触发器,看起来是这样的: <bean id="batchProcessCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="batchProcessJobDetail" /> <property name="cronExpression" value="0 30 2 *
<bean id="batchProcessCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="batchProcessJobDetail" />
<property name="cronExpression" value="0 30 2 * * ?" />
</bean>
如果在凌晨2-3点期间发生了多个配置,我应该如何解决这个问题?是否有公认的最佳实践
相关链接:
基本上它说的是“处理它”,但我的问题是如何处理 我使用一个单独的触发器解决了这个问题,对于东部凌晨2点到3点之间发生的配置,该触发器只在DST开始日期触发(提前一小时)
看起来很笨拙,但它能工作…我们使用以下解决方案。为此,您还需要joda时间库
public class MyCronExpression extends CronExpression
{
CronExpression _orgCronExpression;
public MyCronExpression(String cronExpression) throws ParseException
{
super(cronExpression);
setTimeZone(TimeZone.getTimeZone("UTC"));
_orgCronExpression = new CronExpression(cronExpression);
}
@Override
public Date getTimeAfter(Date date)
{
Date date1 = super.getTimeAfter(new Date(date.getTime()-date.getTimezoneOffset()*60*1000));
if (TimeZone.getDefault().inDaylightTime( date1 ) && !TimeZone.getDefault().inDaylightTime( date ))
{
DateTimeZone dtz = DateTimeZone.getDefault();
Date dstEnd = new Date(dtz.nextTransition(date.getTime()));
int dstEndHour = dstEnd.getHours();
int dstDuration = (dtz.getOffset(date1.getTime()) - dtz.getStandardOffset(date1.getTime()))/(60*60*1000);
int hour = date1.getHours()+date1.getTimezoneOffset()/60;
if (hour < dstEndHour && hour >= dstEndHour-dstDuration)
return dstEnd;
else
return _orgCronExpression.getTimeAfter(date);
}
else
return _orgCronExpression.getTimeAfter(date);
}
}
以下是一些触发时间示例:
Tue Mar 25 02:15:00 CET 2014
Wed Mar 26 02:15:00 CET 2014
Thu Mar 27 02:15:00 CET 2014
Fri Mar 28 02:15:00 CET 2014
Sat Mar 29 02:15:00 CET 2014
**Sun Mar 30 03:00:00 CEST 2014**
Mon Mar 31 02:15:00 CEST 2014
Tue Apr 01 02:15:00 CEST 2014
Wed Apr 02 02:15:00 CEST 2014
如果您发现此解决方案存在任何错误/问题,请发布。我接受了Ron非常有趣的答案,并改进了getTimeAfter方法,以便将其调整为服务器GMT运行以及“每年一次”安排cron表达式时可能出现的差异
@Override
public Date getTimeAfter(Date date) {
Date nextDate = super.getTimeAfter(date);
if(nextDate == null){
return null;
}
DateTime date1 = new DateTime(nextDate);
if (getTimeZone().inDaylightTime(date1.toDate()) && !getTimeZone().inDaylightTime(date)) {
DateTimeZone dtz = DateTimeZone.forTimeZone(getTimeZone());
DateTime dstEndDateTime = new DateTime(new Date(dtz.nextTransition(date.getTime())));
int dstEndHour = dstEndDateTime.getHourOfDay();
int dstDuration = (dtz.getOffset(date1.getMillis()) - dtz.getStandardOffset(date1.getMillis())) / (60 * 60 * 1000);
int hour = date1.getHourOfDay();
// Verifies if the scheduled hour is within a phantom hour (dissapears upon DST change)
if (hour < dstEndHour && hour >= dstEndHour-dstDuration){
// Verify if the date is a skip, otherwise it is a date in the future (like threads that run once a year)
if(dstEndDateTime.getDayOfYear() == date1.minusDays(1).getDayOfYear()){
return dstEndDateTime.toDate();
}else{
return nextDate;
}
}else{
return nextDate;
}
} else{
return nextDate;
}
}
实际上,这似乎是因为温哥华的DST更改发生在3月9日凌晨2点,并且super.getTimeAfter(date)方法的内部实现似乎总是发送null
我希望这些信息有用。JBristow,还有其他方法不需要创建单独的触发器。检查罗恩的答案或我的答案。这当然需要编写一些代码,而不仅仅是通过XML。不幸的是,我不知道这是否满足我们的需要,因为已经四年了,我不再使用这些代码了。威尔,谢谢你的反馈。我已经与美国/温哥华解决了这个问题。我已经将该解决方案集成到一个新项目中:CronExpression类是最后一个类。您是如何扩展它的?最终版本是在2.2.0版中引入的。请使用旧版本或修补当前版本,或者如果您不需要quartz switch的所有功能,请转到我的项目yacron4j,其中实施了DST处理,并且will824报告的问题已得到解决。
@Override
public Date getTimeAfter(Date date) {
Date nextDate = super.getTimeAfter(date);
if(nextDate == null){
return null;
}
DateTime date1 = new DateTime(nextDate);
if (getTimeZone().inDaylightTime(date1.toDate()) && !getTimeZone().inDaylightTime(date)) {
DateTimeZone dtz = DateTimeZone.forTimeZone(getTimeZone());
DateTime dstEndDateTime = new DateTime(new Date(dtz.nextTransition(date.getTime())));
int dstEndHour = dstEndDateTime.getHourOfDay();
int dstDuration = (dtz.getOffset(date1.getMillis()) - dtz.getStandardOffset(date1.getMillis())) / (60 * 60 * 1000);
int hour = date1.getHourOfDay();
// Verifies if the scheduled hour is within a phantom hour (dissapears upon DST change)
if (hour < dstEndHour && hour >= dstEndHour-dstDuration){
// Verify if the date is a skip, otherwise it is a date in the future (like threads that run once a year)
if(dstEndDateTime.getDayOfYear() == date1.minusDays(1).getDayOfYear()){
return dstEndDateTime.toDate();
}else{
return nextDate;
}
}else{
return nextDate;
}
} else{
return nextDate;
}
}
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
String cron = "0 15 2 8 3 ? 2015";
FailsafeCronExpression cronExpression = new FailsafeCronExpression(cron);
cronExpression.setTimeZone(DateTimeZone.forID("America/Vancouver"));
DateTime nextDate = new DateTime(cronExpression.getTimeAfter(sdf.parse("12/11/2014 10:15:00")));