java 构造 Quartz Cron 表达式

java 构造 Quartz Cron 表达式

构造 Quartz Cron 表达式

Quartz Cron 表达式由 6 或 7 个字段组成,分别代表:

字段允许值允许的特殊字符
0-59, - * /
0-59, - * /
0-23, - * /
1-31, - * ? / L W C
1-12 或 JAN-DEC, - * /
周几1-7 或 SUN-SAT, - * ? / L C #
年(可选)
  • 关键说明和注意事项​
  • 在 ​Linux Crontab​ 中,0代表星期日,1代表星期一,2代表星期二,依此类推。
  • 在 ​Quartz​ 中,1代表星期日,2代表星期一,3代表星期二,依此类推。​这是最常见的混淆点!​​
  • 参考: https://www.cnblogs.com/knqiufan/p/18952882

代码实现


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 构造 Quartz Cron 表达式
 * Quartz Cron 表达式由 6 或 7 个字段组成,分别代表:
 * <p>
 * 字段         允许值           允许的特殊字符
 * •秒           0-59             , - * /
 * •分           0-59             , - * /
 * •时           0-23             , - * /
 * •日           1-31             , - * ? / L W C
 * •月           1-12 或 JAN-DEC  , - * /
 * •周几         1-7 或 SUN-SAT    , - * ? / L C #
 * •年(可选)
 * <p>
 * 关键说明和注意事项​
 * 在 ​Linux Crontab​ 中,0代表星期日,1代表星期一,2代表星期二,依此类推。
 * 在 ​Quartz​ 中,1代表星期日,2代表星期一,3代表星期二,依此类推。​这是最常见的混淆点!​​
 * 参考: https://www.cnblogs.com/knqiufan/p/18952882
 */

public class CronExpressionGenerator {

    // 星期名称到Cron表达式数字的映射
    private static final Map<String, Integer> DAY_OF_WEEK_MAP = new HashMap<>();

    static {
        DAY_OF_WEEK_MAP.put("周一", 2);
        DAY_OF_WEEK_MAP.put("周二", 3);
        DAY_OF_WEEK_MAP.put("周三", 4);
        DAY_OF_WEEK_MAP.put("周四", 5);
        DAY_OF_WEEK_MAP.put("周五", 6);
        DAY_OF_WEEK_MAP.put("周六", 7);
        DAY_OF_WEEK_MAP.put("周日", 1);

        DAY_OF_WEEK_MAP.put("星期一", 2);
        DAY_OF_WEEK_MAP.put("星期二", 3);
        DAY_OF_WEEK_MAP.put("星期三", 4);
        DAY_OF_WEEK_MAP.put("星期四", 5);
        DAY_OF_WEEK_MAP.put("星期五", 6);
        DAY_OF_WEEK_MAP.put("星期六", 7);
        DAY_OF_WEEK_MAP.put("星期日", 1);
    }

    public static void main(String[] args) {
        // scanner();

        int choice = 3;
        String time = "11:11";
        String dayInput = "10";
        //String dayInput = "10";
        generateCronExpression(choice, dayInput, time);
    }

    public static String generateCronExpression(int choice, String dayInput, String time) {
        String cronExpression = "";
        switch (choice) {
            case 1:
                cronExpression = generateDailyCron(time);
                break;
            case 2:
                cronExpression = generateWeeklyCron(dayInput, time);
                break;
            case 3:
                cronExpression = generateMonthlyCron(dayInput, "y", time);
                break;
            default:
                throw new IllegalArgumentException("无效的choice类型");
        }
        return cronExpression;
    }

    private static void scanner() {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请选择定时类型:");
        System.out.println("1. 按日执行");
        System.out.println("2. 按周执行");
        System.out.println("3. 按月执行");

        int choice = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        String cronExpression = "";

        switch (choice) {
            case 1:
                cronExpression = scannerDailyCron(scanner);
                break;
            case 2:
                cronExpression = scannerWeeklyCron(scanner);
                break;
            case 3:
                cronExpression = scannerMonthlyCron(scanner);
                break;
            default:
                System.out.println("无效选择");
                return;
        }

        System.out.println("生成的Quartz Cron表达式: " + cronExpression);
        scanner.close();
    }

    /**
     * 生成按日执行的Cron表达式
     */
    private static String scannerDailyCron(Scanner scanner) {
        System.out.println("请输入执行时间 (格式: HH:mm,如 12:00):");
        String time = scanner.nextLine();
        return generateDailyCron(time);
    }

    /**
     * 生成按日执行的Cron表达式
     */
    private static String generateDailyCron(String time) {
        String[] parts = splitTime(time);
        int hour = Integer.parseInt(parts[0]);
        int minute = Integer.parseInt(parts[1]);
        validateTime(hour, minute);
        // Cron格式: 秒 分 时 日 月 星期
        return String.format("0 %d %d * * ?", minute, hour);
    }

    /**
     * 生成按周执行的Cron表达式
     */
    private static String scannerWeeklyCron(Scanner scanner) {
        System.out.println("请输入星期几 (如: 周一):");
        String dayOfWeekInput = scanner.nextLine();

        System.out.println("请输入执行时间 (格式: HH:mm,如 02:00):");
        String time = scanner.nextLine();

        return generateWeeklyCron(dayOfWeekInput, time);
    }

    /**
     * 生成按周执行的Cron表达式
     */
    private static String generateWeeklyCron(String dayOfWeekInput, String time) {
        String[] parts = splitTime(time);

        int hour = Integer.parseInt(parts[0]);
        int minute = Integer.parseInt(parts[1]);

        validateTime(hour, minute);

        Integer dayOfWeek = DAY_OF_WEEK_MAP.get(dayOfWeekInput);
        if (dayOfWeek == null) {
            throw new IllegalArgumentException("无效的星期输入");
        }
        // Cron格式: 秒 分 时 日 月 星期
        return String.format("0 %d %d ? * %d", minute, hour, dayOfWeek);
    }

    /**
     * 生成按月执行的Cron表达式
     */
    private static String scannerMonthlyCron(Scanner scanner) {
        System.out.println("请输入每月的第几天 (1-31),或输入 'L' 表示最后一天:");
        String dayInput = scanner.nextLine().trim();
        String response = "";
        int dayOfMonth;
        if (!"L".equalsIgnoreCase(dayInput)) {
            try {
                dayOfMonth = Integer.parseInt(dayInput);
                if (dayOfMonth < 1 || dayOfMonth > 31) {
                    throw new IllegalArgumentException("日期必须在1-31之间");
                }
                // 对于29、30、31日,提示用户可能的问题
                if (dayOfMonth >= 29) {
                    System.out.println("注意: 选择" + dayOfMonth + "日可能导致在某些月份(如2月)不执行任务。");
                    System.out.println("是否希望使用当月最后一天代替? (y/n)");
                    response = scanner.nextLine().trim();
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("请输入有效的数字(1-31)或'L'表示最后一天");
            }
        }
        System.out.println("请输入执行时间 (格式: HH:mm,如 02:00):");
        String time = scanner.nextLine();
        return generateMonthlyCron(dayInput, response, time);
    }

    /**
     * 生成按月执行的Cron表达式
     *
     * @param dayInput 请输入有效的数字(1-31)或'L'表示最后一天
     * @param response 对于29、30、31日 是否进行转换为最后一天 'L'
     * @param time     执行时间 HH:mm 格式
     */
    private static String generateMonthlyCron(String dayInput, String response, String time) {

        boolean useLastDay = false;
        int dayOfMonth = 1;

        if ("L".equalsIgnoreCase(dayInput)) {
            useLastDay = true;
        } else {
            try {
                dayOfMonth = Integer.parseInt(dayInput);
                if (dayOfMonth < 1 || dayOfMonth > 31) {
                    throw new IllegalArgumentException("日期必须在1-31之间");
                }
                // 对于29、30、31日,提示用户可能的问题
                if (dayOfMonth >= 29) {
                    if ("y".equalsIgnoreCase(response) || "是".equalsIgnoreCase(response)) {
                        useLastDay = true;
                    }
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("请输入有效的数字(1-31)或'L'表示最后一天");
            }
        }

        String[] parts = splitTime(time);

        int hour = Integer.parseInt(parts[0]);
        int minute = Integer.parseInt(parts[1]);

        validateTime(hour, minute);

        // Cron格式: 秒 分 时 日 月 星期
        if (useLastDay) {
            return String.format("0 %d %d L * ?", minute, hour);
        } else {
            return String.format("0 %d %d %d * ?", minute, hour, dayOfMonth);
        }
    }

    private static String[] splitTime(String time) {
        String[] parts = time.split(":");
        if (parts.length != 2) {
            throw new IllegalArgumentException("时间格式不正确,请使用 HH:mm 格式");
        }
        return parts;
    }

    /**
     * 验证时间格式是否正确
     */
    private static void validateTime(int hour, int minute) {
        if (hour < 0 || hour > 23) {
            throw new IllegalArgumentException("小时必须在0-23之间");
        }
        if (minute < 0 || minute > 59) {
            throw new IllegalArgumentException("分钟必须在0-59之间");
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值