人,
我有用户安排的月度工作(使用Quartz)。用户提供开始日期f 或者第一份工作,可能是1-31个月的任何一天
我的问题是如何使用cron触发器安排此操作,记住并非所有月份都有31,30,29天。 在这种情况下,作业应该在最接近的前一天运行。 所以,让我们说四月只有30天,所以工作必须在4月30日运行。
可以使用单个cron触发器完成吗?或者它应该是触发器的组合? 我尝试使用CronExpression来了解它如何处理这种情况:
CronExpression ce = new CronExpression("0 0 0 30 JAN-DEC ? *");
Date nextValidTime = ce.getNextValidTimeAfter(//**27th of February**//);
我的nextValidTime等于 3月30日,所以cron只是“跳过”2月。 任何帮助将受到高度赞赏。提前谢谢。
答案 0 :(得分:6)
“L”字符允许用于日期和星期几字段。该字符>是“最后”的简称,但它在两个领域中都有不同的含义。对于 例如,日期字段中的值“L”表示“最后一天 本月“ - 1月31日,2月28日非飞跃 年份。如果在周日字段中单独使用,则仅表示“7” 或“SAT”。但如果在星期几字段中使用了另一个值,那么 表示“该月的最后一个xxx日” - 例如“6L”表示“ 这个月的最后一个星期五“。你也可以指定一个偏移量 这个月的最后一天,例如“L-3”,这意味着 日历月的倒数第三天。当使用'L'选项时,它 重要的是不要像你那样指定列表或值范围 令人困惑/意外的结果。
http://quartz-scheduler.org/api/2.0.0/org/quartz/CronExpression.html
new CronExpression("0 0 0 L JAN-DEC ? *");
修改强>
我会做这样的事情
Calendar tCalendar = Calendar.getInstance();
tCalendar.set(2009, Calendar.FEBRUARY/*int*/, 1); // for example Feb, 2009 -- day doesn't matter here
if(userSelectedDay > tCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) ){
//Fix user day
//fixedDay = tCalendar.getActualMaximum(Calendar.DAY_OF_MONTH)
// Or, for that month
//new CronExpression("0 0 0 L JAN-DEC ? *");
}
答案 1 :(得分:1)
这是我的解决方案。这个想法是试图构建一组cron表达式,这些表达式将被传递给触发器生成器。
如果输入日期=31。请使用该月的最后一天。
public static Set<String> byDay(int day) {
if (day < 1 || day > 31) {
throw new IllegalArgumentException("The input day must be in range: 1 <= day <= 31");
}
if (day <= 28) {
return Collections.singleton(String.format("0 0 0 %d JAN-DEC ? *", day));
}
if (day == 29 || day == 30) {
Set<String> expressions = new HashSet<String>();
expressions.add("0 0 0 L FEB ? *");
expressions.add(String.format("0 0 0 %d JAN,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC ? *", day));
return Collections.unmodifiableSet(expressions);
}
// day == 31
return Collections.singleton("0 0 0 L * ? *");
}
答案 2 :(得分:0)
尝试使用此代码段,它会根据日期创建1到3个触发器(涵盖整整一年):
Set<Trigger> triggers = new HashSet<>(3);
CronScheduleBuilder interval = CronScheduleBuilder.monthlyOnDayAndHourAndMinute(dayNumber, 0, 0);
if (dayNumber > 28) {
CronTrigger trigger28 = TriggerBuilder.newTrigger()
.withIdentity("payment_trigger28_" + merchantServiceTemplate.getId(), "payment_triggers")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 28 2 ? *"))
.endAt(merchantServiceTemplate.getEndScheduleDate())
.build();
triggers.add(trigger28);
if (dayNumber == 31) {
CronTrigger trigger30 = TriggerBuilder.newTrigger()
.withIdentity("payment_trigger30_" + merchantServiceTemplate.getId(), "payment_triggers")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 30 4,6,9,11 ? *"))
.endAt(merchantServiceTemplate.getEndScheduleDate())
.build();
triggers.add(trigger30);
}
}
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("payment_triggerAll_" + merchantServiceTemplate.getId(), "payment_triggers")
.withSchedule(interval)
.endAt(merchantServiceTemplate.getEndScheduleDate())
.build();
triggers.add(trigger);
scheduler.scheduleJob(job, triggers, false);
答案 3 :(得分:0)
如前所述,您必须为每个月的日期创建多个CronExpressions,并为每个案例创建一个触发器,然后将所有触发器添加到您所需的作业中。
这是我的版本:
CronExpressions创作:
public static List<CronExpression> getCronExpressionList(int seconds, int minutes,
int hours, int dayInMonth, Month month,
DayOfWeek dayOfWeek) {
final String monthsWith30Days = Month.APR + "," + Month.JUN + ","
+ Month.SEP + "," + Month.NOV;
List<CronExpression> crons = new LinkedList<CronExpression>();
String timeString = String.format(("%s %s %s "), seconds, minutes,
hours, 0, 0, 0);
String dateString = "%s %s %s";
String cron = null;
cron = timeString + String.format(dateString, dayInMonth, "*", "?");
crons.add(new CronExpression(cron));
if (dayInMonth > 28) {
String febCron = timeString + getFebruarLastDayDateString(dateString);
crons.add(new CronExpression(febCron));
if (dayInMonth == 31) {
String monthsWithThirtyDaysCron = timeString + String.format(dateString,
"L", monthsWith30Days, "?");
crons.add(new CronExpression(monthsWithThirtyDaysCron));
}
}
return crons;
}
private static String getFebruarLastDayDateString(String initialCron)
throws ParseException {
return String.format(initialCron, "L", Month.FEB, "?");
}
注意我使用&#34; L&#34;在2月份的cron中,因为否则你会在闰年中出现错误。
触发器创建:
Set<CronTrigger> triggers = new HashSet<>();
int i = 1;
for (CronExpression cronEx : cronsList) {
CronTrigger trigger = newTrigger()
.withIdentity("trigger" + i, groupName)
.withSchedule(cronSchedule(cronEx))
.build();
triggers.add(trigger);
i++;
}