我正在使用 Quartz 和 Java 来安排作业。一件事是我将 cron 表达式存储在数据库中,并且我想以更易读的形式将它们呈现给用户。所以我想知道是否有一个实用程序可以将 cron 表达式转换为人类可读的字符串。就像是 :
“”0 30 10-13?* WED,FRI”将变为“每周三和周五的 10:30、11:30、12:30 和 13:30 开火”。
我正在使用 Quartz 和 Java 来安排作业。一件事是我将 cron 表达式存储在数据库中,并且我想以更易读的形式将它们呈现给用户。所以我想知道是否有一个实用程序可以将 cron 表达式转换为人类可读的字符串。就像是 :
“”0 30 10-13?* WED,FRI”将变为“每周三和周五的 10:30、11:30、12:30 和 13:30 开火”。
一个将 cron 表达式转换为人类可读字符串的 Java 库:https ://github.com/RedHogs/cron-parser
嗯,是的,我确实理解你的问题。但我应该更好地解释我的答案。
不,我不知道有任何工具可以帮助您以“人类”可读形式获得 cron 表达式。但是通过访问 CronExpression,您可以创建自己的。
试着打电话
cronTrigger.getExpressionSummary()
关于 cron 表达式:
"0/2 * * 4 * ?"
它返回以下字符串:
seconds: 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58
minutes: *
hours: *
daysOfMonth: 4
months: *
daysOfWeek: ?
lastdayOfWeek: false
nearestWeekday: false
NthDayOfWeek: 0
lastdayOfMonth: false
calendardayOfWeek: false
calendardayOfMonth: false
years: *
通过访问 CronExpression 对象,您可以创建自己的“人类”解释。
cron-utils可能对这项任务有用,因为它提供了人类可读的描述,并且不需要完全成熟的调度程序来提供它们。有据可查并支持多种 cron 格式。
下面是来自文档的代码片段:
//create a descriptor for a specific Locale
CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
//parse some expression and ask descriptor for description
String description = descriptor.describe(parser.parse("*/45 * * * * *"));
//description will be: "every 45 seconds"
这是我开始的。它使用我的用户将(可能)理解的语言。
对于 dayofmonth 令牌,它不会像 '1,13,16-23,L' 这样的令牌混合做得很好,但希望在我的用户变得如此复杂之前,我会有一些时间花在它上面:
包 com.tacteonltd.control.cron; 导入 java.util.StringTokenizer; 导入 com.tacteonltd.control.string.STRING; 导入 com.tacteonltd.control.time.TIME; 公共类 CRON { 公共静态字符串humanReadable(字符串值){ StringBuffer sb = new StringBuffer(); 尝试{ StringTokenizer tokens = new StringTokenizer(value, " ", false); humanizeSeconds(tokens.nextToken(), sb);sb.append("\n"); humanizeMinutes(tokens.nextToken(), sb);sb.append("\n"); humanizeHours(tokens.nextToken(), sb);sb.append("\n"); 字符串 dom = tokens.nextToken(); 字符串月份 = tokens.nextToken(); 字符串 do = tokens.nextToken(); humanizeDOMs(dom, dow, sb);sb.append("\n"); humanizeMonths(月, sb);sb.append("\n"); humanizeDOWs(dow, dom, sb); }catch(可投掷的 t){ t.printStackTrace(); } 返回 sb.toString(); } private static void humanizeDOWs(String value, String dom, StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("and the " + value + postFix(value) + " day-of-the-week("+TIME.getWeekDayName(Integer.parseInt(value))+"). "); } 否则 if(value.equals("*")) { sb.append("以及每周的每一天。"); } 否则 if(value.equals("?")) { sb.append("以及星期几"+(STRING.isNumeric(dom) ? "":"s")+"-of-the-month :"+(STRING.isNumeric (dom) ? dom:"那个匹配"+(STRING.isNumeric(dom) ? "es":"")+" " + dom + ".")); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); sb.append("and the " + first + postFix(first) + " day-of-the-week and every " + every + " day" + (Integer.parseInt(every) == 1 ? "":"s ") + " 跟随。"); } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("以及一周中的以下几天:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ 字符串令牌 = tokens.nextToken(); sb.append((add==0 ? "":", ") + token); added++; } sb.append("."); } 否则 if(value.indexOf("-")>-1){ StringTokenizer tokens = new StringTokenizer(value, "-", false); sb.append("一周中的每一天,从 " + tokens.nextToken() + " 到 " + tokens.nextToken() + ". "); } 别的 { sb.append("以及一周中接下来的几天:" + value + "."); } } 私人静态无效humanizeMonths(字符串值,StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("" + value + postFix(value) + " month("+TIME.getMonthName(Integer.parseInt(value))+"), "); } 否则 if(value.equals("*")) { sb.append("每个月,"); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); sb.append("the " + first + postFix(first) + " month("+TIME.getMonthName(Integer.parseInt(value))+") and every " + every + "month" + (Integer.parseInt(every ) == 1 ? "":"s") + " 以下, "); } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("接下来的月份:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ sb.append((add==0 ? "":", ") + tokens.nextToken()); added++; } } } private static void humanizeDOMs(String value, String dow, StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("" + value + postFix(value) + " day-of-the-month, "); } 否则 if(value.equals("*")) { sb.append("每月的每一天, "); } 否则 if(value.equals("?")) { sb.append("当月的某一天落在 " + dow + " , "); } 否则 if(value.indexOf("-")>-1){ StringTokenizer tokens = new StringTokenizer(value, "-", false); 来自 = tokens.nextToken() 的字符串; 字符串通过 = tokens.nextToken(); int 年 = TIME.getYear(System.currentTimeMillis()); int 月 = TIME.getMonth(System.currentTimeMillis()); String last_dom = "" + TIME.getLastDOM(year, month); sb.append("对于从" + from + "到" + (through.equals("L") ? "the last("+year +"." +month + "."+last_dom+" 的每一天)“:通过) ); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); sb.append("the " + first + postFix(first) + " day-of-the-month and every " + every + " day" + (Integer.parseInt(every) == 1 ? "":"s" ) + " 跟随, "); } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("一个月的下几天:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ 字符串令牌 = tokens.nextToken(); if(token.equals("L")){ int 年 = TIME.getYear(System.currentTimeMillis()); int 月 = TIME.getMonth(System.currentTimeMillis()); String last_dom = "" + TIME.getLastDOM(year, month); sb.append((add==0 ? "":", ") + "the last("+year +"." +month + "."+last_dom+")"); } 别的{ sb.append((add==0 ? "":", ") + token); added++; } } } } 私人静态无效humanizeSeconds(字符串值,StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("上" + value + postFix(value) + " second, "); } 否则 if(value.equals("*")) { sb.append("每隔一秒,"); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); sb.append("在 " + first + postFix(first) + " second and every " + every + " second" + (Integer.parseInt(every) == 1 ? "":"s") + " 后面, "); } 否则 if(value.indexOf("-")>-1){ StringTokenizer tokens = new StringTokenizer(value, "-", false); sb.append("从 " + tokens.nextToken() + " 到 " + tokens.nextToken() + " ") 的每一秒; } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("在接下来的几秒:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ sb.append((add==0 ? "":", ") + tokens.nextToken()); added++; } } } 私人静态无效humanizeMinutes(字符串值,StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("" + value + postFix(value) + " minute, "); } 否则 if(value.equals("*")) { sb.append("每分钟,"); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); " ); } 否则 if(value.indexOf("-")>-1){ StringTokenizer tokens = new StringTokenizer(value, "-", false); sb.append("从 " + tokens.nextToken() + " 到 " + tokens.nextToken() + " ") 的每一分钟; } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("接下来的分钟数:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ sb.append((add==0 ? "":", ") + tokens.nextToken()); added++; } } } 私人静态无效humanizeHours(字符串值,StringBuffer sb){ 值=值.trim(); 如果(字符串.isNumeric(值)){ sb.append("" + value + postFix(value) + " hour, "); } 否则 if(value.equals("*")) { sb.append("每小时, "); } 否则 if(value.indexOf("/")>-1){ String first = value.substring(0, value.indexOf("/")); 每个字符串 = value.substring(value.indexOf("/") + 1); sb.append("" + first + postFix(first) + " hour and every " + every + " hour" + (Integer.parseInt(every) == 1 ? "":"s") + " following, " ); } 否则 if(value.indexOf("-")>-1){ StringTokenizer tokens = new StringTokenizer(value, "-", false); sb.append("从 " + tokens.nextToken() + " 到 " + tokens.nextToken() + " ") 的每个小时; } 否则 if(value.indexOf(",")>-1){ StringTokenizer tokens = new StringTokenizer(value, ",", false); sb.append("接下来的时间:"); 整数添加= 0; 而(令牌。hasMoreTokens()){ sb.append((add==0 ? "":", ") + tokens.nextToken()); added++; } } } 私有静态字符串后缀(字符串值){ 字符串帖子=空; if(value.substring(value.length()-1).equals("1"))post = "st"; 否则 if(value.substring(value.length()-1).equals("2"))post = "nd"; 否则 if(value.substring(value.length()-1).equals("3"))post = "rd"; 否则 post="th"; 回帖; } }
The CronTrigger creates a CronExpression object from the cron expression String. But you cannot get access to it. But by using reflection you can:
Class c = cronTrigger.getClass();
Field f = c.getDeclaredField("cronEx");
f.setAccessible(true);
CronExpression cronEx = (CronExpression) f.get(cronTrigger);