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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章