解析Cron表达式为中文白话文

文章介绍了一种方法,用于将cron表达式解析成易于理解的中文描述,适用于不熟悉cron表达式的技术人员。通过引入spring-boot-starter-quartz依赖进行cron表达式的格式校验,然后逐个解析月、日、时、分、秒各个域,支持特定的特殊符号如L、W等。该方法可以方便地将复杂的定时任务配置转化为直观的中文说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        项目上有个功能要手动配置cron表达式用于定时调度,为了方便对cron表达式不太熟悉的操作人员使用,编写了一个解析cron表达式为中文白话的方法,支持数字、符号、字母组成的表达式,不支持包含英文缩写。用的是比较笨的方式一个一个解析,略显粗劣,供大家参考交流。

首先要引入依赖,这个是为了借助其他组件来校验cron表达式的格式是否正确,这样可以专注于表达式的解析

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>

然后就是代码了

首先是入口方法,做cron表达式的校验,取出各域的值调用解析方法

public static String cronParse(String cron) {
        StringBuilder stringBuilder = new StringBuilder();
        boolean monthFlag = false;
        boolean dayFlag = false;
        boolean hourFlag = false;
        boolean minuteFlag = false;
        //通过new CronExpression对象的形式验证cron表达式格式是否正确
        try {
            CronExpression expression = new CronExpression(cron);
        } catch (Exception e) {
            StackTraceElement[] stackTrace = e.getStackTrace();
            stringBuilder.append("表达式解析失败:").append(Arrays.toString(stackTrace));
            return stringBuilder.toString();
        }
        List<String> cronList = Arrays.asList(cron.split(" "));
        //解析月
        StringBuilder month = splice(cronList, 4, false, "年",12,  "月");
        if(month != null){
            monthFlag = true;
            stringBuilder.append(month);
        }
        //日
        // L这个月最后一天
        // 15W 本月最接近15号的工作日
        // LW 本月最后一个工作日
        StringBuilder day = splice(cronList, 3, monthFlag, "月", 31,  "日");
        if(day != null){
            dayFlag = true;
            stringBuilder.append(day);
        }
        //周
        // L这一周的最后一天   5L 这个月的最后一个星期五
        // # 6#3  第三个周五
        StringBuilder week = spliceWeek(cronList, 5, monthFlag, "月", 7,  "月");
        if(week != null){
            dayFlag = true;
            stringBuilder.append(week);
        }
        //时
        StringBuilder hour = splice(cronList, 2, dayFlag, "日", 23,  "时");
        if(hour != null){
            hourFlag = true;
            stringBuilder.append(hour);
        }
        //分
        StringBuilder minute = splice(cronList, 1, hourFlag, "时", 59,  "分");
        if(minute != null){
            minuteFlag = true;
            stringBuilder.append(minute);
        }
        //秒
        StringBuilder second = splice(cronList, 0, minuteFlag, "分", 59,  "秒");
        if(second != null){
            stringBuilder.append(second);
        }
        return stringBuilder.toString();

    }

解析方法解析月 日 时 分 秒

/**
     *
     * @param cronList cron表达式转list
     * @param index 当前解析的域的位置
     * @param superFlag 当前解析等级是否需要带上级 如表达式表达每小时执行,那么无需解析为每日每小时执行,可不带上级日
     * @param superLevel 前解析等级的上级  如月的上级是年
     * @param bigSize 当前解析等级最大的数 如月最大是12
     * @param levelShort 当前等级的名称简写
     * @return
     */
    private static StringBuilder splice(List<String> cronList, int index, Boolean superFlag, String superLevel, Integer bigSize, String levelShort){
        StringBuilder stringBuilder = new StringBuilder();
        String cron = cronList.get(index);
        //*或者?无需解析
        if(!cron.contains("*") && !cron.contains("?")){
            // "/"代表从某时刻开始,每隔多久执行一次
            if(cron.contains("/")){
                String[] split = cron.split("/");
                int begin = Integer.parseInt(split[0]);
                int interVal = Integer.parseInt(split[1]);
                //如果/前的数是当前域的最小值且间隔时间是1,则表示每..执行
                if(interVal == 1){
                    if((begin == 0 && index != 4) || (begin == 1 && index == 4)){
                        stringBuilder.append("每").append(levelShort);
                    }
                }else {
                    if(superFlag){
                        stringBuilder.append("的");
                    }else {
                        stringBuilder.append("每").append(superLevel).append("的");
                    }
                    for (int i = 0; begin <= bigSize; i++){
                        if(i == 0){
                            stringBuilder.append(begin).append(levelShort);
                        }else {
                            stringBuilder.append(",").append(begin).append(levelShort);
                        }
                        begin += interVal;
                    }
                }
                // "-"表示范围
            }else if(cron.contains("-")){
                String[] split = cron.split("-");
                Integer begin = Integer.parseInt(split[0]);
                Integer end = Integer.parseInt(split[1]);
                if(superFlag){
                    stringBuilder.append("的");
                }else {
                    stringBuilder.append("每").append(superLevel).append("的");
                }
                for (int i = 0; begin <= end; i++){
                    if(i == 0){
                        stringBuilder.append(begin).append(levelShort);
                    }else {
                        stringBuilder.append(",").append(begin).append(levelShort);
                    }
                    begin++;
                }
             // ","表示枚举
            }else if(cron.contains(",")){
                List<String> list = Arrays.asList(cron.split(","));
                if(superFlag){
                    stringBuilder.append("的");
                }else {
                    stringBuilder.append("每").append(superLevel).append("的");
                }
                for (int i = 0; i < list.size(); i++){
                    String num = list.get(i);
                    if(i == 0){
                        stringBuilder.append(num).append(levelShort);
                    }else {
                        stringBuilder.append(",").append(num).append(levelShort);
                    }
                }
            }
            //日
            // L这个月最后一天
            // 15W 本月最接近15号的工作日
            // LW 本月最后一个工作日
            else if(index == 3 && "L".equals(cron)){
                if(superFlag){
                    stringBuilder.append("的").append("最后一天");
                }else {
                    stringBuilder.append("每").append(superLevel).append("最后一天");
                }
            }else if(index == 3 && "LW".equals(cron)){
                if(superFlag){
                    stringBuilder.append("的").append("最后一个工作日");
                }else {
                    stringBuilder.append("每").append(superLevel).append("最后一个工作日");
                }
            }else if(index == 3 && cron.contains("W")){
                String dayNear = cron.substring(0, cron.length() - 1);
                if(superFlag){
                    stringBuilder.append("的").append("最接近").append(dayNear).append("日的工作日");
                }else {
                    stringBuilder.append("每").append(superLevel).append("最接近").append(dayNear).append("日的工作日");
                }
            }
            //周
            // L这一周的最后一天   5L 这个月的最后一个星期五
            // # 6#3  第三个周五
            else if(index == 5 && "L".equals(cron)){
                if(superFlag){
                    stringBuilder.append("的").append("每个星期日");
                }else {
                    stringBuilder.append("每").append(superLevel).append("每个星期日");
                }
            }
            else {
                if(superFlag){
                    stringBuilder.append("的").append(cron).append(levelShort);
                }else {
                    stringBuilder.append("每").append(superLevel).append(cron).append(levelShort);
                }
            }
            return stringBuilder;
        }else {
            return null;
        }
    }

表达式最后一位需要单独解析

private static StringBuilder spliceWeek(List<String> cronList, int index, Boolean superFlag, String superLevel, Integer bigSize, String levelShort){
        StringBuilder stringBuilder = new StringBuilder();
        String cron = cronList.get(index);
        if(!cron.contains("*") && !cron.contains("?")){
            if(cron.contains("/")){
                String[] split = cron.split("/");
                Integer begin = Integer.parseInt(split[0]);
                Integer interVal = Integer.parseInt(split[1]);
                if(begin == 0 && interVal == 1){
                    stringBuilder.append("每").append("一天");
                }else {
                    if(superFlag){
                        stringBuilder.append("的");
                    }else {
                        stringBuilder.append("每").append(superLevel).append("的");
                    }
                    for (int i = 0; begin <= bigSize; i++){
                        if(i == 0){
                            stringBuilder.append(begin).append(levelShort);
                        }else {
                            stringBuilder.append(",").append(numToWeek(begin));
                        }
                        begin += interVal;
                    }
                }
            }else if(cron.contains("-")){
                String[] split = cron.split("-");
                int begin = Integer.parseInt(split[0]);
                int end = Integer.parseInt(split[1]);
                if(superFlag){
                    stringBuilder.append("的");
                }else {
                    stringBuilder.append("每").append(superLevel).append("的");
                }
                for (int i = 0; begin <= end; i++){
                    if(i == 0){
                        stringBuilder.append(numToWeek(begin));
                    }else {
                        stringBuilder.append(",").append(numToWeek(begin));
                    }
                    begin++;
                }

            }else if(cron.contains(",")){
                List<String> list = Arrays.asList(cron.split(","));
                if(superFlag){
                    stringBuilder.append("的");
                }else {
                    stringBuilder.append("每").append(superLevel).append("的");
                }
                for (int i = 0; i < list.size(); i++){
                    String num = list.get(i);
                    if(i == 0){
                        stringBuilder.append(num).append(levelShort);
                    }else {
                        stringBuilder.append(",").append(numToWeek(Integer.parseInt(num)));
                    }
                }
            }
            //周
            // L这一周的最后一天   5L 这个月的最后一个星期五
            // # 6#3  第三个周五
            else if(index == 5 && "L".equals(cron)){
                if(superFlag){
                    stringBuilder.append("的").append("每个星期日");
                }else {
                    stringBuilder.append("每").append(superLevel).append("每个星期日");
                }
            }
            else if(index == 5 && cron.contains("L")){
                String dayNear = cron.substring(0, cron.length() - 1);
                if(superFlag){
                    stringBuilder.append("的").append("最后一个").append(numToWeek(Integer.parseInt(dayNear)));
                }else {
                    stringBuilder.append("每").append(superLevel).append("的最后一个").append(numToWeek(Integer.parseInt(dayNear)));
                }
            }
            else if(index == 5 && cron.contains("#")){
                String[] split = cron.split("#");
                String weekNum = split[0];
                String weekOrder = split[1];
                String dayNear = cron.substring(0, cron.length() - 1);
                if(superFlag){
                    stringBuilder.append("的").append("第").append(weekOrder).append("个").append(numToWeek(Integer.parseInt(weekNum)));
                }else {
                    stringBuilder.append("每").append(superLevel).append("第").append(weekOrder).append("个").append(numToWeek(Integer.parseInt(weekNum)));
                }
            }
            else {
                if(superFlag){
                    stringBuilder.append("的").append("每个").append(numToWeek(Integer.parseInt(cron)));
                }else {
                    stringBuilder.append("每个").append(numToWeek(Integer.parseInt(cron)));
                }
            }
            return stringBuilder;
        }else {
            return null;
        }
    }

    private static String numToWeek(Integer num){
        switch (num){
            case 1:
                return "星期日";
            case 2:
                return "星期一";
            case 3:
                return "星期二";
            case 4:
                return "星期三";
            case 5:
                return "星期四";
            case 6:
                return "星期五";
            case 7:
                return "星期六";
            default:
                break;
        }
        return "";

    }

调用效果如下

public static void main(String[] args) {
        String s = cronParse("0 0/1 11,13 * 1/1 ?");
        System.out.println(s);
    }

每月每日的11时,13时每分的0秒

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值