cron 衝突檢測,檢查多個cron表示式執行時間點是否有重合
阿新 • • 發佈:2019-01-07
基於spring 的 CronSequenceGenerator 修改,增加了年的檢測,年支援到1970~2099年
package com.hshbic.cloud.rcs.common.util; import org.quartz.impl.triggers.CronTriggerImpl; import java.text.ParseException; import java.util.*; /** * cron 表示式計算器 * Created by Liu xianan on 2018/4/20. */ public class CronCalculateUtil { /*** 下一次觸發時間 * * @return */ public static Date nextTriggerTime(String cron, Date current) throws ParseException { CronTriggerImpl cronTrigger = new CronTriggerImpl(); cronTrigger.setCronExpression(cron); return cronTrigger.getFireTimeAfter(current); } /** * cron 衝突檢測* @return */ public static boolean cronIsConflict(String... crons) { BitSet[][] bitSetMatrix=new BitSet[crons.length][7]; for(int i=0;i<crons.length;i++){ bitSetMatrix[i]=getCronBitSet(crons[i]); } for (int i=0;i<7;i++){ BitSet bitSetResult = null;for (int j=0;j<bitSetMatrix.length;j++){ BitSet current = bitSetMatrix[j][i]; if(bitSetResult==null){ bitSetResult=current; }else { bitSetResult.and(current); } } if(bitSetResult.length()<=0){ return false; } } return true; } private static BitSet[] getCronBitSet(String cron) { BitSet[] bitSets =new BitSet[7]; CronSequenceGenerator cronSequenceGenerator1; try { cronSequenceGenerator1=new CronSequenceGenerator(cron); }catch (Exception e){ throw new IllegalArgumentException(e.getMessage()); } bitSets[0] = cronSequenceGenerator1.getSeconds(); bitSets[1] = cronSequenceGenerator1.getMinutes(); bitSets[2] = cronSequenceGenerator1.getHours(); bitSets[3] = cronSequenceGenerator1.getDaysOfWeek(); bitSets[4] = cronSequenceGenerator1.getDaysOfMonth(); bitSets[5] = cronSequenceGenerator1.getMonths(); bitSets[6] = cronSequenceGenerator1.getYear(); return bitSets; } }
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.hshbic.cloud.rcs.common.util; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; import java.util.TimeZone; import org.springframework.util.StringUtils; public class CronSequenceGenerator { private final BitSet seconds; private final BitSet minutes; private final BitSet hours; private final BitSet daysOfWeek; private final BitSet daysOfMonth; private final BitSet months; private final BitSet year; private final String expression; private final TimeZone timeZone; public CronSequenceGenerator(String expression) { this(expression, TimeZone.getDefault()); } public CronSequenceGenerator(String expression, TimeZone timeZone) { this.seconds = new BitSet(60); this.minutes = new BitSet(60); this.hours = new BitSet(24); this.daysOfWeek = new BitSet(7); this.daysOfMonth = new BitSet(31); this.months = new BitSet(12); this.year = new BitSet(129); this.expression = expression; this.timeZone = timeZone; this.parse(expression); } private void parse(String expression) throws IllegalArgumentException { String[] fields = StringUtils.tokenizeToStringArray(expression, " "); if (fields.length != 6&&fields.length != 7) { throw new IllegalArgumentException(String.format("Cron expression must consist of 6 or 7 fields (found %d in \"%s\")", fields.length, expression)); } else { this.setNumberHits(this.seconds, fields[0], 0, 60); this.setNumberHits(this.minutes, fields[1], 0, 60); this.setNumberHits(this.hours, fields[2], 0, 24); this.setDaysOfMonth(this.daysOfMonth, fields[3]); this.setMonths(this.months, fields[4]); this.setDays(this.daysOfWeek, this.replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8); if (this.daysOfWeek.get(7)) { this.daysOfWeek.set(0); this.daysOfWeek.clear(7); } if(fields.length==7){ this.setNumberHits(this.year,fields[6],1970,2100); }else { this.setNumberHits(this.year,"1970-2099",1970,2100); } } } private String replaceOrdinals(String value, String commaSeparatedList) { String[] list = StringUtils.commaDelimitedListToStringArray(commaSeparatedList); for(int i = 0; i < list.length; ++i) { String item = list[i].toUpperCase(); value = StringUtils.replace(value.toUpperCase(), item, "" + i); } return value; } private void setDaysOfMonth(BitSet bits, String field) { int max = 31; this.setDays(bits, field, max + 1); bits.clear(0); } private void setDays(BitSet bits, String field, int max) { if (field.contains("?")) { field = "*"; } this.setNumberHits(bits, field, 0, max); } private void setMonths(BitSet bits, String value) { int max = 12; value = this.replaceOrdinals(value, "FOO,JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"); BitSet months = new BitSet(13); this.setNumberHits(months, value, 1, max + 1); for(int i = 1; i <= max; ++i) { if (months.get(i)) { bits.set(i - 1); } } } private void setNumberHits(BitSet bits, String value, int min, int max) { String[] fields = StringUtils.delimitedListToStringArray(value, ","); String[] arr$ = fields; int len$ = fields.length; for(int i$ = 0; i$ < len$; ++i$) { String field = arr$[i$]; if (!field.contains("/")) { int[] range = this.getRange(field, min, max); bits.set(range[0], range[1] + 1); } else { String[] split = StringUtils.delimitedListToStringArray(field, "/"); if (split.length > 2) { throw new IllegalArgumentException("Incrementer has more than two fields: '" + field + "' in expression \"" + this.expression + "\""); } int[] range = this.getRange(split[0], min, max); if (!split[0].contains("-")) { range[1] = max - 1; } int delta = Integer.valueOf(split[1]); if(delta==0){ throw new IllegalArgumentException("Incrementer 2nd field cannot be 0: '" + field + "' in expression \"" + this.expression + "\""); } for(int i = range[0]; i <= range[1]; i += delta) { bits.set(i); } } } } private int[] getRange(String field, int min, int max) { int[] result = new int[2]; if (field.contains("*")) { result[0] = min; result[1] = max - 1; return result; } else { if (!field.contains("-")) { result[0] = result[1] = Integer.valueOf(field); } else { String[] split = StringUtils.delimitedListToStringArray(field, "-"); if (split.length > 2) { throw new IllegalArgumentException("Range has more than two fields: '" + field + "' in expression \"" + this.expression + "\""); } result[0] = Integer.valueOf(split[0]); result[1] = Integer.valueOf(split[1]); } if (result[0] < max && result[1] < max) { if (result[0] >= min && result[1] >= min) { return result; } else { throw new IllegalArgumentException("Range less than minimum (" + min + "): '" + field + "' in expression \"" + this.expression + "\""); } } else { throw new IllegalArgumentException("Range exceeds maximum (" + max + "): '" + field + "' in expression \"" + this.expression + "\""); } } } String getExpression() { return this.expression; } public boolean equals(Object obj) { if (!(obj instanceof CronSequenceGenerator)) { return false; } else { CronSequenceGenerator cron = (CronSequenceGenerator)obj; return cron.months.equals(this.months) && cron.daysOfMonth.equals(this.daysOfMonth) && cron.daysOfWeek.equals(this.daysOfWeek) && cron.hours.equals(this.hours) && cron.minutes.equals(this.minutes) && cron.seconds.equals(this.seconds); } } public int hashCode() { return 37 + 17 * this.months.hashCode() + 29 * this.daysOfMonth.hashCode() + 37 * this.daysOfWeek.hashCode() + 41 * this.hours.hashCode() + 53 * this.minutes.hashCode() + 61 * this.seconds.hashCode(); } public BitSet getSeconds() { return seconds; } public BitSet getMinutes() { return minutes; } public BitSet getHours() { return hours; } public BitSet getDaysOfWeek() { return daysOfWeek; } public BitSet getDaysOfMonth() { return daysOfMonth; } public BitSet getMonths() { return months; } public BitSet getYear() { return year; } public TimeZone getTimeZone() { return timeZone; } @Override public String toString() { return "CronSequenceGenerator{" + "seconds=" + seconds + ", minutes=" + minutes + ", hours=" + hours + ", daysOfWeek=" + daysOfWeek + ", daysOfMonth=" + daysOfMonth + ", months=" + months + ", year=" + year + ", expression='" + expression + '\'' + ", timeZone=" + timeZone + '}'; } }