本篇不算原创,因为主要内容来自网上的博客,所以给出我参考文章的链接。

本文cron表达式详解的大部分内容参考了[cron表达式详解]和Quartz使用总结、Cron表达式 这两篇文章。

cron校验的内容参考了 判断cron表达式输入是否有效的正则表达式Verifying a cron expression is valid in Java 这两篇文章。


一、表达式组成

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:

Seconds Minutes Hours DayofMonth Month DayofWeek Year或 Seconds Minutes Hours DayofMonth Month DayofWeek

位置 时间域 允许值 特殊值
1 0-59 , - * /
2 分钟 0-59 , - * /
3 小时 0-23 , - * /
4 日期 1-31 , - * ? / L W C
5 月份 1-12 , - * /
6 星期 1-7 , - * ? / L C #
7 年份(可选) 留空, 1970-2099 , - * /

每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:

(1) *:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。

(2) ? :只能用在DayofMonth和DayofWeek两个域。因为DayofMonth和 DayofWeek会相互影响,所以按我的理解?应该是占位符。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用,而不能使用*

(3) - :表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

(4) /:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

(5) , :表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。

(6) L :表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

(7) W: 表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一 到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份

(8) LW :这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

(9) # :用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

难点解析

本篇主要看6个字符的表达式。cron本身是很容易理解的,单个拆开来看,都很容易理解。但是全部写起来却容易出问题。例如,我们想写一个每天都执行的表达式。如果是新手的话,我们可能下意识地会这样写:

0 0 0 * * *

这样写理由很充分,因为每天0时0分0秒嘛,所以前三个都是0,日期、月份和星期都是任意的,所以全是*。但是事实上"月份中的日期"和"星期中的日期"这两个元素互斥的,例如你设置了每月1号又设置了每周一,我们可以理解为cron表达式不能处理或的关系。所以正确的写法是:

0 0 0 * * ?

有些其他的例子把?解释为匹配任意字符,实际这不准确。我的理解是?代表一个无用的占位符,一个cron表达式要么设置每月的日期,要么设置星期中的日期,否则就是错误的。假如你需要这种每月1号或者每周周一执行的任务,那么你应该用两个cron表达式。

二、cron表达式例子

cron表达式 描述
0 0 10,15,16 * * ? 每天上午10点,下午3点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
0 0 12 * * ? 每天中午12点触发
0 15 10 ? * * 每天上午10:15触发
0 15 10 * * ? 每天上午10:15触发 (跟上面的一样)
0 15 10 * * ? 2005 2005年的每天上午10:15触发
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
0 15 10 15 * ? 每月15日上午10:15触发
0 15 10 L * ? 每月最后一日的上午10:15触发
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发

三、验证Cron

验证一个cron表达式有很多种方法,这里我们介绍两种。

  1. 正则表达式方法(不推荐)
  String regEx = "^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?)*))$";
String tests = "0 0 0 * * ?";
System.out.println(tests.matches(regEx));

这里真的不建议用正则匹配的方法验证cron表达式,一是匹配规则太复杂几乎没法修改,二是容易出错(由评论区@HLMK 指出)。比如上述的正则中0 0 0 L * ?就不能匹配到,所以强烈建议你使用CronExpression包进行验证。

  1. CronExpression验证

这个方法需要引入quartz的jar包,然后只需要一行代码就可以验证了。

CronExpression.isValidExpression(cron)

参考文章

Cron validation regex generator (based on http://stackoverflow.com/questions/2362985/verifying-a-cron-expression-is-valid-in-java)

Cron表达式详解和表达式的验证的更多相关文章

  1. crontab和cron表达式详解

    引言 我们在定时任务中经常能接触到cron表达式,但是在写cron表达式的时候我们会遇到各种各样版本的cron表达式,比如我遇到过5位.6位甚至7位的cron表达式,导致我一度搞混这些表达式.更严重的 ...

  2. cron表达式详解

    @Scheduled(cron = "* * * * * *") cron表达式详解 1.cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份( ...

  3. spring定时任务(@Scheduled注解)cron表达式详解

    cron表达式详解: 一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素. 按顺序依次为 秒(~) 分钟(~) 小时(~) 天(~) 月(~) 星期(~ =SUN 或 SUN,MON,TU ...

  4. Quartz.Net系列(九):Trigger之CronScheduleBuilder和Cron表达式详解

    1.使用 var scheduler =await StdSchedulerFactory.GetDefaultScheduler(); await scheduler.Start(); var jo ...

  5. JAVA8之lambda表达式详解

    原文:http://blog.csdn.net/jinzhencs/article/details/50748202 lambda表达式详解 一.问题 1.什么是lambda表达式? 2.lambda ...

  6. Lambda表达式详解(例子详解)(转自:http://blog.csdn.net/damon316/article/details/51734661)

    Lambda表达式详解(例子详解)     lambda简介 lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 ...

  7. zabbix3.4.7触发器表达式详解

    zabbix触发器表达式详解 概述:触发器中的表达式使用很灵活,我们可以创建一个复杂的逻辑测试监控,触发器表达式形式如下: {<server>:<key>.<functi ...

  8. Spring定时器corn表达式详解

    1.结构 Spring定时器corn表达式详解 2.各字段的含义 字段 允许值 允许的特殊字符 秒 0~59 - * / 分 0~59 - * / 小时 0~23 - * / 日期 1~31 - * ...

  9. Java 8 Lambda 表达式详解

    一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...

随机推荐

  1. Node.js(daemon),tweak(debug ES)/nodejs forever,supervisor--express

    http://www.cnblogs.com/Darren_code/p/node_express.html express -e nodejs-product sudo npm install fo ...

  2. Docker,docker-machine,docker-composer

    https://docs.docker.com/engine/installation/mac/ Docker值得关注的特性文件系统隔离:每个进程容器运行在一个完全独立的根文件系统里.资源隔离:系统资 ...

  3. 学习计划 mysql explain执行计划任务详解

    我们在之前已经找到了需要优化的SQL,但是怎么知道它的那些方面需要优化呢? explain就是为了这个使用的. explain显示了 mysql 如何使用索引来处理select语句以及连接表.可以帮助 ...

  4. 聊一聊Linux中的工作队列

    2018-01-18 工作队列是Linux内核中把工作延迟执行的一种手段,其目的不同于软中断,软中断是提高CPU的响应,尽可能的缩短关中断的时间:而工作队列主要目的是节省资源,其比较适合很微小的任务, ...

  5. Why String is Immutable or Final in Java

    The string is Immutable in Java because String objects are cached in String pool. Since cached Strin ...

  6. python 基础3 函数

    函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或 ...

  7. dedecms调用当前栏目的子栏目怎么操作

    有时我们建网站会建很多分类,每个分类又有小分类,为了让顶级栏目获得更好的权重和排名,我们会聚合子栏目.那么dedecms调用当前栏目的子栏目怎么操作呢? 有两种方法:标签dede:sonchannel ...

  8. CentOS工作内容(五)单一网卡配置多个IP

    CentOS工作内容(五)单一网卡配置多个IP 用到的快捷键 tab 自动补齐(有不知道的吗) ctrl+a 移动到当前行的开头(a ahead) ctrl+e 移动到当前行的开头(e end) ct ...

  9. Jquery-plugins-toastr-消息提示

    toastr是一个基于jQuery简单.漂亮的消息提示插件,使用简单.方便,可以根据设置的超时时间自动消失. 1.使用很简单,首选引入toastr的js.css文件 html <link rel ...

  10. 安装HDF5及在VS下配置HDF5

    最近要用到HDF5来存储数据,想要安装尝试用一下.发现网上有两种安装方式,一种是obtain518.html:获取最新的HDF5-1.8软件;另一种是cmakebuild518.html:使用CMAK ...