1. 程式人生 > >cron 衝突檢測,檢查多個cron表示式執行時間點是否有重合

cron 衝突檢測,檢查多個cron表示式執行時間點是否有重合

基於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 +
                '}';
}
}