Java中Cron表達式的生成解析及計算的工具類完整代碼
本文介紹通過java生成cron表達式,解析表達式,計算表達式執(zhí)行日期
1. 生成表達式
public static String createCronExpression(CronModel cronModel){ StringBuilder cronExp = new StringBuilder(); if(null == cronModel.getJobType()) { System.out.println("執(zhí)行周期未配置" );//執(zhí)行周期未配置 } 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("月份數(shù)據(jù)異常: "+ 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秒執(zhí)行一次 cron = "0/" + cycle + " * * * * ?"; break; case 1:// 每cycle分鐘執(zhí)行一次 cron = "0 0/" + cycle + " * * * ?"; break; case 2:// 每cycle小時執(zhí)行一次 cron = "0 0 0/" + cycle + " * * ?"; break; case 3:// 每cycle天的0點執(zhí)行一次 cron = "0 0 0 1/" + cycle + " * ?"; break; case 4:// 每cycle月的1號0點執(zhí)行一次 cron = "0 0 0 1 1/" + cycle + " ? "; break; case 5:// 每天cycle點執(zhí)行一次 cron = "0 0 " + cycle+ " * * ?"; break; default:// 默認每cycle秒執(zhí)行一次 cron = "0/1 * * * * ?"; break; } return cron; }
2. 解析表達式
/** * 生成計劃的詳細描述 * *@param cronModel *@return String */ public static String createDescription(CronModel cronModel){ StringBuffer description = new StringBuffer(""); //計劃執(zhí)行開始時間 // 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("執(zhí)行"); } //按每周 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("執(zhí)行"); } //按每月 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("執(zhí)行"); } } return description.toString(); }
3. 計算表達式執(zhí)行日期
需要引入quartz依賴
<dependency> <groupId>quartz</groupId> <artifactId>quartz</artifactId> <version>1.5.2</version> </dependency>
/** * 計算表達式最近幾次執(zhí)行時間 * @param cronExpress 表達式 * @param num 次數(shù) * @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);//按每天 //每隔幾天執(zhí)行 cronModel.setBeApart(1); String cropExp = createCronExpression(cronModel); System.out.println(cropExp + ":" + createDescription(cronModel)); //執(zhí)行時間:每天的12時12分12秒 end System.out.println(getCronNextTimes(cropExp, 5)); cronModel.setJobType(JobEnum.WEEK);//每周的哪幾天執(zhí)行 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);//每月的哪幾天執(zhí)行 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
/** * @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 , - * / * * * 表示所有值; * ? 表示未說明的值,即不關(guān)心它為何值; * - 表示一個指定的范圍; * , 表示附加一個可能值; * / 符號前表示開始時間,符號后表示每次遞增的值; * L("last") ("last") "L" 用在day-of-month字段意思是 "這個月最后一天";用在 day-of-week字段, 它簡單意思是 "7" or "SAT"。 如果在day-of-week字段里和數(shù)字聯(lián)合使用,它的意思就是 "這個月的最后一個星期幾" – 例如: "6L" means "這個月的最后一個星期五". 當我們用“L”時,不指明一個列表值或者范圍是很重要的,不然的話,我們會得到一些意想不到的結(jié)果。 * W("weekday") 只能用在day-of-month字段。用來描敘最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近這個 月第15天的工作日”,即如果這個月第15天是周六,那么觸發(fā)器將會在這個月第14天即周五觸發(fā);如果這個月第15天是周日,那么觸發(fā)器將會在這個月第 16天即周一觸發(fā);如果這個月第15天是周二,那么就在觸發(fā)器這天觸發(fā)。注意一點:這個用法只會在當前月計算值,不會越過當前月?!癢”字符僅能在 day-of-month指明一天,不能是一個范圍或列表。也可以用“LW”來指定這個月的最后一個工作日。 * # 只能用在day-of-week字段。用來指定這個月的第幾個周幾。例:在day-of-week字段用"6#3"指這個月第3個周五(6指周五,3指第3個)。如果指定的日期不存在,觸發(fā)器就不會觸發(fā)。 * C 指和calendar聯(lián)系后計算過的值。例:在day-of-month 字段用“5C”指在這個月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在這周日或之后包括calendar的第一天。 * * */ public class CronUtil { /** * 計算表達式最近幾次執(zhí)行時間 * @param cronExpress 表達式 * @param num 次數(shù) * @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; } /** * 構(gòu)建Cron表達式 * 目前支持三種常用的cron表達式 * 1.每天的某個時間點執(zhí)行 例:12 12 12 * * 表示每天12時12分12秒執(zhí)行 * 2.每周的哪幾天執(zhí)行 例:12 12 12 ? * 1,2,3表示每周的周1周2周3 ,12時12分12秒執(zhí)行 * 3.每月的哪幾天執(zhí)行 例:12 12 12 1,21,13 * ?表示每月的1號21號13號 12時12分12秒執(zhí)行 * * */ public static String createCronExpression(CronModel cronModel){ StringBuilder cronExp = new StringBuilder(); if(null == cronModel.getJobType()) { System.out.println("執(zhí)行周期未配置" );//執(zhí)行周期未配置 } 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("月份數(shù)據(jù)異常: "+ 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(""); //計劃執(zhí)行開始時間 // 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("執(zhí)行"); } //按每周 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("執(zhí)行"); } //按每月 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("執(zhí)行"); } } return description.toString(); } /** * 構(gòu)建Cron表達式 * @param rate 第幾位 * @param cycle 數(shù)值 * @return */ public static String createLoopCronExpression(int rate, int cycle) { String cron = ""; switch (rate) { case 0:// 每cycle秒執(zhí)行一次 cron = "0/" + cycle + " * * * * ?"; break; case 1:// 每cycle分鐘執(zhí)行一次 cron = "0 0/" + cycle + " * * * ?"; break; case 2:// 每cycle小時執(zhí)行一次 cron = "0 0 0/" + cycle + " * * ?"; break; case 3:// 每cycle天的0點執(zhí)行一次 cron = "0 0 0 1/" + cycle + " * ?"; break; case 4:// 每cycle月的1號0點執(zhí)行一次 cron = "0 0 0 1 1/" + cycle + " ? "; break; case 5:// 每天cycle點執(zhí)行一次 cron = "0 0 " + cycle+ " * * ?"; break; default:// 默認每cycle秒執(zhí)行一次 cron = "0/1 * * * * ?"; break; } return cron; } public static void main(String[] args) { CronModel cronModel = new CronModel(); cronModel.setJobType(JobEnum.DAY);//按每天 //每隔幾天執(zhí)行 cronModel.setBeApart(1); String cropExp = createCronExpression(cronModel); System.out.println(cropExp + ":" + createDescription(cronModel)); //執(zhí)行時間:每天的12時12分12秒 end System.out.println(getCronNextTimes(cropExp, 5)); cronModel.setJobType(JobEnum.WEEK);//每周的哪幾天執(zhí)行 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);//每月的哪幾天執(zhí)行 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)); } }
總結(jié)
到此這篇關(guān)于Java中Cron表達式的生成解析及計算的工具類的文章就介紹到這了,更多相關(guān)Java Cron表達式生成解析計算內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Java編程之if-else的優(yōu)化技巧總結(jié)
說實話,其實我很討厭在代碼里大量使用if-else,一是因為該類代碼執(zhí)行方式屬于面向過程的,二嘛,則是會顯得代碼過于冗余.這篇筆記,主要記錄一些自己在工作實踐當中針對if-else的優(yōu)化心得,將會不定期地長期更新,需要的朋友可以參考下2021-06-06idea中解決maven包沖突的問題(maven helper)
這篇文章主要介紹了idea中解決maven包沖突的問題(maven helper),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12MyBatis 中 type-aliases-package的作用(簡化類型映射)
MyBatis中type-aliases-package的作用是簡化類型映射,通過指定包路徑,MyBatis會自動掃描該包下的所有類并為這些類生成類型別名,減少XML配置文件中的冗長代碼,感興趣的朋友跟隨小編一起看看吧2024-11-11Java使用CountDownLatch實現(xiàn)統(tǒng)計任務耗時
這篇文章主要為大家詳細介紹了Java如何使用CountDownLatch實現(xiàn)統(tǒng)計任務耗時的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-06-06