本文介绍通过java生成cron表达式,解析表达式,计算表达式执行日期


1. 生成表达式

public static String createCronExpression(CronModel cronModel){

        StringBuilder cronExp = new StringBuilder();


        if(null == cronModel.getJobType()) {

            System.out.println("执行周期未配置" );//执行周期未配置

        }


        if (null != cronModel.getSecond()

                && null != cronModel.getMinute()

                && null != cronModel.getHour()) {

            //秒

            cronExp.append(cronModel.getSecond()).append(" ");

            //分

            cronExp.append(cronModel.getMinute()).append(" ");

            //小时

            cronExp.append(cronModel.getHour()).append(" ");

            //每天

            if(cronModel.getJobType().getValue() == 1){

                //12 12 12 1/2 * ? *

                //12 12 12 * * ?

                if(cronModel.getBeApart()!=null){

                    cronExp.append("1");//日

                    cronExp.append("/");

                    cronExp.append(cronModel.getBeApart()+1);//月

                    cronExp.append(" ");

                    cronExp.append("* ");

                    cronExp.append("?");

                }else {

                    cronExp.append("* ");//日

                    cronExp.append("* ");//月

                    cronExp.append("?");

                }

            }


            //按每周

            else if(cronModel.getJobType().getValue() == 3){

                //一个月中第几天

                cronExp.append("? ");

                //月份

                cronExp.append("* ");

                //周

                Integer[] weeks = cronModel.getDayOfWeeks();

                for(int i = 0; i < weeks.length; i++){

                    if(i == 0){

                        cronExp.append(weeks[i]);

                    } else{

                        cronExp.append(",").append(weeks[i]);

                    }

                }


            }

            //按每月

            else if(cronModel.getJobType().getValue()== 2){

                //一个月中的哪几天

                Integer[] days = cronModel.getDayOfMonths();

                for(int i = 0; i < days.length; i++){

                    if(i == 0){

                        if(days[i]==32){

                            //本月最后一天

                            String endMouthCron="0 0 0 L * ?";

                            return endMouthCron;

                        }else {

                            cronExp.append(days[i]);

                        }

                    } else{

                        cronExp.append(",").append(days[i]);

                    }

                }

                //月份

                cronExp.append(" * ");

                //周

                cronExp.append("?");

            }

            //按每年

            else if(cronModel.getJobType().getValue()== 4){

                //一个年中的哪几天

                Integer[] days = cronModel.getDayOfMonths();

                if(ArrayUtil.isEmpty(days)){

                    cronExp.append("*");

                }else{

                    for(int i = 0; i < days.length; i++){

                        if(i == 0){

                            cronExp.append(days[i]);

                        } else{

                            cronExp.append(",").append(days[i]);

                        }

                    }

                }

                //月份

                Integer[] months = cronModel.getMonths();

                if (ArrayUtil.isEmpty(months)) {

                    cronExp.append(" *");

                }else{

                    for (int i = 0; i < months.length; i++){

                        Integer month = months[i];

                        if (month > 12){

                            throw new RuntimeException("月份数据异常: "+ Arrays.toString(months));

                        }

                        if(i == 0){

                            cronExp.append(" ").append(month);

                        }else{

                            cronExp.append(",").append(month);

                        }

                    }

                }

                cronExp.append(" ?");

            }

            else if(cronModel.getJobType().getValue() == 0){

                cronExp.append("* ");//日

                cronExp.append("* ");//月

                cronExp.append("?");//周

            }

        }

        return cronExp.toString();

    }

 


public static String createLoopCronExpression(int rate, int cycle) {

        String cron = "";

        switch (rate) {

            case 0:// 每cycle秒执行一次

                cron = "0/" + cycle + " * * * * ?";

                break;

            case 1:// 每cycle分钟执行一次

                cron = "0 0/" + cycle + " * * * ?";

                break;

            case 2:// 每cycle小时执行一次

                cron = "0 0 0/" + cycle + " * * ?";

                break;

            case 3:// 每cycle天的0点执行一次

                cron = "0 0 0 1/" + cycle + " * ?";

                break;

            case 4:// 每cycle月的1号0点执行一次

                cron = "0 0 0 1 1/" + cycle + " ? ";

                break;

            case 5://  每天cycle点执行一次

                cron = "0 0 " + cycle+ "  * * ?";

                break;

            default:// 默认每cycle秒执行一次

                cron = "0/1 * * * * ?";

                break;

        }

        return cron;

    }

 

2. 解析表达式

/**

     * 生成计划的详细描述

     *

     *@param  cronModel

     *@return String

     */

    public static String createDescription(CronModel cronModel){

        StringBuffer description = new StringBuffer("");

        //计划执行开始时间

//      Date startTime = cronModel.getScheduleStartTime();


        if (null != cronModel.getSecond()

                && null != cronModel.getMinute()

                && null != cronModel.getHour()) {

            //按每天

            if(cronModel.getJobType().getValue() == 1){

                Integer beApart = cronModel.getBeApart();

                if(beApart !=null){

                    description.append("每间隔").append(beApart).append("天");

                }else{

                    description.append("每天");

                }

                description.append(cronModel.getHour()).append("时");

                description.append(cronModel.getMinute()).append("分");

                description.append(cronModel.getSecond()).append("秒");

                description.append("执行");

            }


            //按每周

            else if(cronModel.getJobType().getValue() == 3){

                if(cronModel.getDayOfWeeks() != null && cronModel.getDayOfWeeks().length > 0) {

                    String days = "";

                    for(int i : cronModel.getDayOfWeeks()) {

                        days += "周" + i;

                    }

                    description.append("每周的").append(days).append(" ");

                }

                if (null != cronModel.getSecond()

                        && null != cronModel.getMinute()

                        && null != cronModel.getHour()) {

                    description.append(",");

                    description.append(cronModel.getHour()).append("时");

                    description.append(cronModel.getMinute()).append("分");

                    description.append(cronModel.getSecond()).append("秒");

                }

                description.append("执行");

            }


            //按每月

            else if(cronModel.getJobType().getValue() == 2){

                //选择月份

                if(cronModel.getDayOfMonths() != null && cronModel.getDayOfMonths().length > 0) {

                    String days = "";

                    for(int i : cronModel.getDayOfMonths()) {

                        days += i + "号";

                    }

                    description.append("每月的").append(days).append(" ");

                }

                description.append(cronModel.getHour()).append("时");

                description.append(cronModel.getMinute()).append("分");

                description.append(cronModel.getSecond()).append("秒");

                description.append("执行");

            }


        }

        return description.toString();

    }

 

3. 计算表达式执行日期

需要引入quartz依赖


<dependency>

    <groupId>quartz</groupId>

    <artifactId>quartz</artifactId>

    <version>1.5.2</version>

</dependency>

 

/**

     * 计算表达式最近几次执行时间

     * @param cronExpress 表达式

     * @param num 次数

     * @return 时间集合

     */

    public static List<String> getCronNextTimes(String cronExpress,Integer num){

        if(StrUtil.isEmpty(cronExpress)){

            throw new RuntimeException("cron 表达式不能为空");

        }

        //判断cron表达式

        if(!CronSequenceGenerator.isValidExpression(cronExpress)){

            throw new RuntimeException("cron 表达式格式不正确,cron: "+cronExpress);

        }

        if(num == null || num == 0){

            num = 1;

        }

        List<String> list = new ArrayList<>();

        CronTrigger cronTrigger = new CronTrigger();

        try {

            cronTrigger.setCronExpression(cronExpress);

        } catch (ParseException e) {

            throw new RuntimeException("cron表达式不正确,cron: "+cronExpress);

        }

        List<Date> dates = TriggerUtils.computeFireTimes(cronTrigger, null, num);

        String format = "yyyy-MM-dd HH:mm:ss";

        for (Date date : dates) {

            list.add(DateUtil.format(date,format));

        }

        return list;

    }

 

4. 测试

public static void main(String[] args) {

        CronModel cronModel = new CronModel();

        cronModel.setJobType(JobEnum.DAY);//按每天

        //每隔几天执行

        cronModel.setBeApart(1);

        String cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        //执行时间:每天的12时12分12秒 end

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.WEEK);//每周的哪几天执行

        Integer[] dayOfWeeks = new Integer[3];

        dayOfWeeks[0] = 1;

        dayOfWeeks[1] = 2;

        dayOfWeeks[2] = 3;

        cronModel.setDayOfWeeks(dayOfWeeks);

        cronModel.setJobType(JobEnum.WEEK);

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.MONTH);//每月的哪几天执行

        Integer[] dayOfMonths = new Integer[3];

        dayOfMonths[0] = 1;

        dayOfMonths[1] = 21;

        dayOfMonths[2] = 13;

        cronModel.setDayOfMonths(dayOfMonths);

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.EVERY);//每天的几点几分几秒开始

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp);

        System.out.println(getCronNextTimes(cropExp, 5));


    }

 



5. 完整代码

gitee地址:


https://gitee.com/zhenglm/tools.git

1

/**

 * @author zlm

 * @date 2023/8/3

 */

public enum JobEnum {


    EVERY("每天",0),

    DAY("日",1),

    MONTH("月",2),

    WEEK("周",3),

    YEAR("年",4),

    ;


    JobEnum(String name,Integer value) {

        this.name = name;

        this.value = value;

    }


    private final String name;

    private final Integer value;


    public Integer getValue() {

        return value;

    }


    public String getName() {

        return name;

    }

}


 

public class CronModel {


    Integer[] dayOfWeeks;


    Integer[] dayOfMonths;


    Integer[] months;


    Integer second;


    Integer minute;


    Integer hour;


    /**

     * 类型

     */

    JobEnum jobType;

    /**

     * 间隔

     */

    Integer beApart;


    public Integer[] getDayOfWeeks() {

        return dayOfWeeks;

    }


    public void setDayOfWeeks(Integer[] dayOfWeeks) {

        this.dayOfWeeks = dayOfWeeks;

    }


    public Integer[] getDayOfMonths() {

        return dayOfMonths;

    }


    public void setDayOfMonths(Integer[] dayOfMonths) {

        this.dayOfMonths = dayOfMonths;

    }


    public Integer[] getMonths() {

        return months;

    }


    public void setMonths(Integer[] months) {

        this.months = months;

    }


    public Integer getSecond() {

        return second == null ? 0 : second;

    }


    public void setSecond(Integer second) {

        this.second = second;

    }


    public Integer getMinute() {

        return minute == null ? 0 : minute;

    }


    public void setMinute(Integer minute) {

        this.minute = minute;

    }


    public Integer getHour() {


        return hour==null ? 0 : hour;

    }


    public void setHour(Integer hour) {

        this.hour = hour;

    }


    public JobEnum getJobType() {

        return jobType == null ? JobEnum.DAY : jobType;

    }


    public void setJobType(JobEnum jobType) {

        this.jobType = jobType;

    }


    public Integer getBeApart() {

        return beApart;

    }


    public void setBeApart(Integer beApart) {

        this.beApart = beApart;

    }

}


 

/**

 * @author zlm

 * @date 2023/8/3

 *

 * 字段 允许值 允许的特殊字符

 * 秒 0-59 , – * /

 * 分 0-59 , – * /

 * 小时 0-23 , – * /

 * 日期 1-31 , – * ? / L W C

 * 月份 1-12 或者 JAN-DEC , – * /

 * 星期 1-7 或者 SUN-SAT , – * ? / L C #

 * 年(可选) 留空, 1970-2099 , – * /

 *

 * * 表示所有值;

 * ? 表示未说明的值,即不关心它为何值;

 * – 表示一个指定的范围;

 * , 表示附加一个可能值;

 * / 符号前表示开始时间,符号后表示每次递增的值;

 * L("last") ("last") "L" 用在day-of-month字段意思是 "这个月最后一天";用在 day-of-week字段, 它简单意思是 "7" or "SAT"。 如果在day-of-week字段里和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" means "这个月的最后一个星期五". 当我们用“L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。

 * W("weekday") 只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个 月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第 16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在 day-of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日。

 * # 只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。

 * C 指和calendar联系后计算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天。

 *

 *

 */

public class CronUtil {

    

    /**

     * 计算表达式最近几次执行时间

     * @param cronExpress 表达式

     * @param num 次数

     * @return 时间集合

     */

    public static List<String> getCronNextTimes(String cronExpress,Integer num){

        if(StrUtil.isEmpty(cronExpress)){

            throw new RuntimeException("cron 表达式不能为空");

        }

        //判断cron表达式

        if(!CronSequenceGenerator.isValidExpression(cronExpress)){

            throw new RuntimeException("cron 表达式格式不正确,cron: "+cronExpress);

        }

        if(num == null || num == 0){

            num = 1;

        }

        List<String> list = new ArrayList<>();

        CronTrigger cronTrigger = new CronTrigger();

        try {

            cronTrigger.setCronExpression(cronExpress);

        } catch (ParseException e) {

            throw new RuntimeException("cron表达式不正确,cron: "+cronExpress);

        }

        List<Date> dates = TriggerUtils.computeFireTimes(cronTrigger, null, num);

        String format = "yyyy-MM-dd HH:mm:ss";

        for (Date date : dates) {

            list.add(DateUtil.format(date,format));

        }

        return list;

    }


    /**

     *  构建Cron表达式

     * 目前支持三种常用的cron表达式

     * 1.每天的某个时间点执行 例:12 12 12 * * 表示每天12时12分12秒执行

     * 2.每周的哪几天执行    例:12 12 12 ? * 1,2,3表示每周的周1周2周3 ,12时12分12秒执行

     * 3.每月的哪几天执行    例:12 12 12 1,21,13 * ?表示每月的1号21号13号 12时12分12秒执行

     *

     *

     */

    public static String createCronExpression(CronModel cronModel){

        StringBuilder cronExp = new StringBuilder();


        if(null == cronModel.getJobType()) {

            System.out.println("执行周期未配置" );//执行周期未配置

        }


        if (null != cronModel.getSecond()

                && null != cronModel.getMinute()

                && null != cronModel.getHour()) {

            //秒

            cronExp.append(cronModel.getSecond()).append(" ");

            //分

            cronExp.append(cronModel.getMinute()).append(" ");

            //小时

            cronExp.append(cronModel.getHour()).append(" ");

            //每天

            if(cronModel.getJobType().getValue() == 1){

                //12 12 12 1/2 * ? *

                //12 12 12 * * ?

                if(cronModel.getBeApart()!=null){

                    cronExp.append("1");//日

                    cronExp.append("/");

                    cronExp.append(cronModel.getBeApart()+1);//月

                    cronExp.append(" ");

                    cronExp.append("* ");

                    cronExp.append("?");

                }else {

                    cronExp.append("* ");//日

                    cronExp.append("* ");//月

                    cronExp.append("?");//周

                }

            }


            //按每周

            else if(cronModel.getJobType().getValue() == 3){

                //一个月中第几天

                cronExp.append("? ");

                //月份

                cronExp.append("* ");

                //周

                Integer[] weeks = cronModel.getDayOfWeeks();

                for(int i = 0; i < weeks.length; i++){

                    if(i == 0){

                        cronExp.append(weeks[i]);

                    } else{

                        cronExp.append(",").append(weeks[i]);

                    }

                }


            }

            //按每月

            else if(cronModel.getJobType().getValue()== 2){

                //一个月中的哪几天

                Integer[] days = cronModel.getDayOfMonths();

                for(int i = 0; i < days.length; i++){

                    if(i == 0){

                        if(days[i]==32){

                            //本月最后一天

                            String endMouthCron="0 0 0 L * ?";

                            return endMouthCron;

                        }else {

                            cronExp.append(days[i]);

                        }

                    } else{

                        cronExp.append(",").append(days[i]);

                    }

                }

                //月份

                cronExp.append(" * ");

                //周

                cronExp.append("?");

            }

            //按每年

            else if(cronModel.getJobType().getValue()== 4){

                //一个年中的哪几天

                Integer[] days = cronModel.getDayOfMonths();

                if(ArrayUtil.isEmpty(days)){

                    cronExp.append("*");

                }else{

                    for(int i = 0; i < days.length; i++){

                        if(i == 0){

                            cronExp.append(days[i]);

                        } else{

                            cronExp.append(",").append(days[i]);

                        }

                    }

                }

                //月份

                Integer[] months = cronModel.getMonths();

                if (ArrayUtil.isEmpty(months)) {

                    cronExp.append(" *");

                }else{

                    for (int i = 0; i < months.length; i++){

                        Integer month = months[i];

                        if (month > 12){

                            throw new RuntimeException("月份数据异常: "+ Arrays.toString(months));

                        }

                        if(i == 0){

                            cronExp.append(" ").append(month);

                        }else{

                            cronExp.append(",").append(month);

                        }

                    }

                }

                cronExp.append(" ?");

            }

            else if(cronModel.getJobType().getValue() == 0){

                cronExp.append("* ");//日

                cronExp.append("* ");//月

                cronExp.append("?");//周

            }

        }

        return cronExp.toString();

    }


    /**

     * 生成计划的详细描述

     *

     *@param  cronModel

     *@return String

     */

    public static String createDescription(CronModel cronModel){

        StringBuffer description = new StringBuffer("");

        //计划执行开始时间

//      Date startTime = cronModel.getScheduleStartTime();


        if (null != cronModel.getSecond()

                && null != cronModel.getMinute()

                && null != cronModel.getHour()) {

            //按每天

            if(cronModel.getJobType().getValue() == 1){

                Integer beApart = cronModel.getBeApart();

                if(beApart !=null){

                    description.append("每间隔").append(beApart).append("天");

                }else{

                    description.append("每天");

                }

                description.append(cronModel.getHour()).append("时");

                description.append(cronModel.getMinute()).append("分");

                description.append(cronModel.getSecond()).append("秒");

                description.append("执行");

            }


            //按每周

            else if(cronModel.getJobType().getValue() == 3){

                if(cronModel.getDayOfWeeks() != null && cronModel.getDayOfWeeks().length > 0) {

                    String days = "";

                    for(int i : cronModel.getDayOfWeeks()) {

                        days += "周" + i;

                    }

                    description.append("每周的").append(days).append(" ");

                }

                if (null != cronModel.getSecond()

                        && null != cronModel.getMinute()

                        && null != cronModel.getHour()) {

                    description.append(",");

                    description.append(cronModel.getHour()).append("时");

                    description.append(cronModel.getMinute()).append("分");

                    description.append(cronModel.getSecond()).append("秒");

                }

                description.append("执行");

            }


            //按每月

            else if(cronModel.getJobType().getValue() == 2){

                //选择月份

                if(cronModel.getDayOfMonths() != null && cronModel.getDayOfMonths().length > 0) {

                    String days = "";

                    for(int i : cronModel.getDayOfMonths()) {

                        days += i + "号";

                    }

                    description.append("每月的").append(days).append(" ");

                }

                description.append(cronModel.getHour()).append("时");

                description.append(cronModel.getMinute()).append("分");

                description.append(cronModel.getSecond()).append("秒");

                description.append("执行");

            }


        }

        return description.toString();

    }



    /**

     * 构建Cron表达式

     * @param rate 第几位

     * @param cycle 数值

     * @return

     */

    public static String createLoopCronExpression(int rate, int cycle) {

        String cron = "";

        switch (rate) {

            case 0:// 每cycle秒执行一次

                cron = "0/" + cycle + " * * * * ?";

                break;

            case 1:// 每cycle分钟执行一次

                cron = "0 0/" + cycle + " * * * ?";

                break;

            case 2:// 每cycle小时执行一次

                cron = "0 0 0/" + cycle + " * * ?";

                break;

            case 3:// 每cycle天的0点执行一次

                cron = "0 0 0 1/" + cycle + " * ?";

                break;

            case 4:// 每cycle月的1号0点执行一次

                cron = "0 0 0 1 1/" + cycle + " ? ";

                break;

            case 5://  每天cycle点执行一次

                cron = "0 0 " + cycle+ "  * * ?";

                break;

            default:// 默认每cycle秒执行一次

                cron = "0/1 * * * * ?";

                break;

        }

        return cron;

    }


    public static void main(String[] args) {

        CronModel cronModel = new CronModel();

        cronModel.setJobType(JobEnum.DAY);//按每天

        //每隔几天执行

        cronModel.setBeApart(1);

        String cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        //执行时间:每天的12时12分12秒 end

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.WEEK);//每周的哪几天执行

        Integer[] dayOfWeeks = new Integer[3];

        dayOfWeeks[0] = 1;

        dayOfWeeks[1] = 2;

        dayOfWeeks[2] = 3;

        cronModel.setDayOfWeeks(dayOfWeeks);

        cronModel.setJobType(JobEnum.WEEK);

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.MONTH);//每月的哪几天执行

        Integer[] dayOfMonths = new Integer[3];

        dayOfMonths[0] = 1;

        dayOfMonths[1] = 21;

        dayOfMonths[2] = 13;

        cronModel.setDayOfMonths(dayOfMonths);

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp + ":" + createDescription(cronModel));

        System.out.println(getCronNextTimes(cropExp, 5));


        cronModel.setJobType(JobEnum.EVERY);//每天的几点几分几秒开始

        cropExp = createCronExpression(cronModel);

        System.out.println(cropExp);

        System.out.println(getCronNextTimes(cropExp, 5));


    }


}



————————————————

版权声明:本文为CSDN博主「*郑*」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_42202992/article/details/132085828