工具介绍
Cron 表达式是一个紧凑的五字段定时字符串——`分钟 小时 日 月 星期`——被 Unix `cron` 守护进程以及几乎所有仿照它设计的任务调度器(crontab、Kubernetes CronJob、GitHub Actions 的 `schedule:`、Airflow、Jenkins)使用。每个字段可以是星号(`*`,表示“任意值”)、一个具体数字、一个用逗号分隔的列表(`1,15,30`)、一个区间(`9-17`)、一个步长(`*/15`,表示“每 15 个单位”),或者——对于月份和星期字段——使用三字母缩写(`JAN`、`MON`)而不是数字。
这种语法的权威定义见于 Linux crontab(5) 手册页,其中记录了完全相同的五个字段、特殊字符(`* , - /`),以及大多数 Cron 实现(包括大多数 Linux 发行版自带的 Vixie cron)都支持的八种 `@` 简写字符串(`@reboot`、`@yearly`/`@annually`、`@monthly`、`@weekly`、`@daily`/`@midnight`、`@hourly`),它们作为常见定时规则的别名。
这个工具实现的正是这种标准的 5 字段格式——也就是你会直接写入 Linux 或 macOS 服务器上 `crontab -e`,或写入 Kubernetes CronJob 的 `schedule:` 字段的格式。它不支持 Quartz Cron 语法,那是一种不同的、6 或 7 字段的格式,被 Java 的 Quartz Scheduler 以及一些厂商工具使用(关于何时需要那种格式,请参见下方的对比章节)。
为什么使用它?
- 接手一个生产环境的 crontab,里面有一行 `17 3 * * 0` 却没有任何注释说明——在动手改之前先粘贴到这里看看,确认它其实是“每周日凌晨3点17分”,而不是手误写错的。
- 写 GitHub Actions 的 `schedule:` 定时触发器,一直拿不准 `0 */6 * * *` 到底是不是“从午夜开始每6小时一次”——提交 YAML 之前先看一下接下来5次的运行时间确认一下。
- 设置了一个同时限制“日”和“星期”的定时任务,比如 `0 4 8 * MON`,结果任务在意料之外的日子触发了——这个工具会直接告诉你这是“或”而不是“且”的并集逻辑,这个坑几乎每个人第一次都会踩。
- 在搭建 Kubernetes CronJob,需要“工作日、仅工作时间、每15分钟一次”对应的确切 `schedule:` 字符串,不想自己数字段——用下拉菜单构建器代替手写。
- 不确定某个调度器的配置用的是标准 Cron 还是 Quartz Cron,因为文档只写了“cron表达式”这四个字——先看看是5个字段(标准Cron,本工具)还是6-7个字段并带有 `?`/`L`/`W`/`#` 字符(Quartz),免得白白花时间排查格式不匹配的问题。
- 100% 本地运行:你的定时逻辑永远不会离开你的浏览器。
使用方法
- 要翻译一个表达式:在输入框中键入或粘贴一个 5 字段的 Cron 字符串(或像 `@daily` 这样的 @ 简写)。
- 阅读下方的通俗说明和计算出的接下来 5 次运行时间——两者都会随着你的输入实时更新。
- 要改为构建表达式:打开“构建器”部分,为五个字段分别选择一种模式(每个 / 每隔 N 个 / 指定值),然后点击“生成表达式”。
- 生成的表达式会填入上方的输入框,并立即反映到说明和接下来运行时间的面板中。
- 使用底部的语法图例,快速查阅 `*`、`,`、`-` 和 `/` 的含义。
- 点击“复制”按钮复制最终的表达式,粘贴到你的 crontab、CI 配置或调度器中。
示例
输入
*/15 9-17 * * MON-FRI输出
在 09:00、09:15、09:30、09:45、10:00……17:45,周一、周二、周三、周四、周五执行这个表达式每 15 分钟运行一次,但仅限于 09:00–17:59 这个小时区间内,并且仅在工作日——这是一种典型的“工作时间”轮询定时规则。
标准 Cron 与 Quartz Cron 对比
“Cron 语法”并不是唯一的通用标准——你最常遇到的两种格式在字段数量以及部分特殊字符的含义上都有所不同。使用下表确认你为目标调度器使用了正确的格式。
| 方面 | 标准 Cron(本工具) | Quartz Cron |
|---|---|---|
| 字段数量 | 5(minute hour dom month dow) | 6 或 7(增加秒字段,以及可选的年份) |
| 使用场景 | Linux/macOS crontab、Kubernetes CronJob、GitHub Actions | Java Quartz Scheduler、部分企业级调度器 |
| “日”和“星期”同时设置 | 匹配任意一个(并集/或) | 两个字段中必须有一个使用 `?` ——不能同时为两者设置具体值 |
| 额外的特殊字符 | 除 `* , - /` 外没有 | 增加了 `?`、`L`(最后一天)、`W`(最近的工作日)、`#`(本月第 n 个星期几) |
| 秒级调度 | 不支持 | 支持(第一个字段) |
常见定时规则速查
少数几个表达式就覆盖了绝大多数实际使用场景——值得直接记住,不用每次都重新推导。
- `*/5 * * * *` —— 全天每5分钟一次。常用于健康检查和轻量级轮询任务。
- `0 */6 * * *` —— 每6小时整点一次(00:00、06:00、12:00、18:00)。常作为周期性同步或清理任务的默认设置。
- `0 2 * * *` —— 每天凌晨2点一次。夜间备份的经典时段,此时流量最低。
- `0 9 * * 1-5` —— 仅工作日(周一到周五)上午9点。常用于只在工作时间发送的报表或摘要。
- `0 0 1 * *` —— 每月1号午夜,等价于 `@monthly` 简写。常用于按月计费或月度使用量重置。
- `*/15 9-17 * * MON-FRI` —— 仅工作日的工作时间内每15分钟一次——在一个表达式里同时组合了步长、区间和星期范围。
相关工具
正在处理配置、定时规则或时间戳?以下工具可以很好地搭配 Cron 生成器使用。
常见问题
什么是 Cron 表达式?
Cron 表达式是一个 5 字段的文本字符串(`分钟 小时 日 月 星期`),用于为 Unix `cron` 守护进程及兼容的调度器指定一个重复执行的定时规则。每个字段可以是 `*`(任意值)、一个数字、一个逗号分隔的列表、一个区间(`a-b`)或一个步长(`*/n`);月份和星期字段还接受像 `JAN` 或 `MON` 这样的三字母缩写。完整规范记录在 crontab(5) 手册页 中。
当“日”和“星期”两个字段都被限制时会发生什么?
这是一个众所周知的 Cron 陷阱:根据 POSIX Cron 语义,当“日”和“星期”两个字段都被限制(即都不是 `*`)时,只要满足其中任意一个条件,任务就会运行——这是并集(或),而不是交集(与)。例如,`0 4 8 * MON` 会在每月 8 号的凌晨 4 点运行,也会在每个周一的凌晨 4 点运行,而不仅仅是恰好落在 8 号的周一。本工具在计算接下来的运行时间时,正是实现了这种并集行为。
标准 Cron 与 Quartz Cron——你需要哪一种?
本工具生成的是标准 5 字段 POSIX/Vixie Cron 语法——即 Linux/macOS 的 `crontab`、Kubernetes CronJob、GitHub Actions 的 `schedule:` 以及大多数源自 Unix 的任务运行器所使用的格式。而 Quartz Cron 被 Java 的 Quartz Scheduler 及基于它构建的工具(一些企业级调度器、较旧的 Spring Batch 配置)使用,是一种不同的 6 或 7 字段格式,它在开头增加了一个秒字段,并改变了一些特殊字符的含义(在日期字段中用 `?` 表示“无特定值”,用 `L`/`W`/`#` 分别表示“最后一天”、“最近的工作日”和“本月第 n 个星期几”)。如果你的调度器需要 6 或 7 个字段,或者其文档中提到了 `?`、`L`、`W` 或 `#`,那么你需要一个专门针对 Quartz 的工具——本生成器生成的表达式在那里无法被正确解析。如果恰好是 5 个字段(或 `@daily` 风格的简写),那么你就用对了工具。
@yearly、@monthly、@weekly、@daily 和 @hourly 这些快捷方式是什么意思?
这些是非标准但被广泛支持的简写字符串,会展开为常见的 5 字段表达式:`@yearly`/`@annually` = `0 0 1 1 *`(每年一次,1 月 1 日午夜),`@monthly` = `0 0 1 * *`(每月 1 号午夜),`@weekly` = `0 0 * * 0`(每周日午夜),`@daily`/`@midnight` = `0 0 * * *`(每天午夜),`@hourly` = `0 * * * *`(每小时整点)。本工具会解析所有这些简写,并将其视为与展开后的 5 字段表达式完全等价。
我可以用星期/月份名称代替数字吗?
可以。月份字段接受从 `JAN` 到 `DEC` 的三字母名称,星期字段接受从 `SUN` 到 `SAT`(不区分大小写),可与数字互换使用。星期数字范围是 0–6,其中 0 = 星期日;一些实现也接受用 7 表示星期日,本工具会将其归一化为 0。区间和列表同样支持使用名称,例如 `MON-FRI` 或 `JAN,JUN,DEC`。
我的 Cron 表达式会被发送到服务器吗?
不会。解析、通俗说明的生成,以及下一次运行时间的计算,全部都在你的浏览器本地用 JavaScript 完成。你输入或生成的任何内容都不会离开你的设备。
接下来的运行时间是按哪个时区计算的?
本工具按你浏览器的本地时区计算接下来的运行时间,因为标准 Cron 本身并没有内置时区字段——实际运行任务的守护进程或调度器会使用其所在主机系统设置的时区(对于 GitHub Actions 等云端调度器则通常是 UTC)。如果你的服务器时区和浏览器时区不同,需要自己在心里做一下时区换算,或者单独确认调度器的时区配置。
怎么设置一个只在每月最后一天运行的任务?
标准 5 字段 Cron 没有直接表示“每月最后一天”的语法——这是 Quartz Cron 用 `L` 字符额外支持的功能。在标准 Cron 里,常见的变通做法是把任务设置为每月 28 到 31 号每天都跑一次(`0 0 28-31 * *`),然后由脚本自己判断“明天”是否已经进入下个月,再决定要不要真正执行逻辑。
可以设置成每隔一个不太规整的时间间隔运行吗,比如每10分钟?
可以,用步长语法:`*/10 * * * *` 表示从整点开始每10分钟运行一次(也就是 :00、:10、:20、:30、:40、:50)。需要注意的是,步长永远是从该字段的最小值开始计数,所以分钟字段里的 `*/10` 永远不会落在 :05 或 :15 上——如果需要这种带偏移量的间隔,改用显式的逗号列表即可,例如 `5,15,25,35,45,55`。
为什么我的 Cron 任务在夏令时切换前后好像跑了两次,或者一次都没跑?
标准 Cron 是按主机系统的挂钟时间来调度的,而夏令时切换会导致某个小时被跳过(春季调快)或者重复出现(秋季调回)。如果任务恰好安排在被跳过或重复的那个小时,当天可能会执行零次或两次,具体表现取决于你所用 Cron 守护进程的处理方式。把关键任务放在设置为 UTC 时区(没有夏令时)的服务器上运行,可以完全避免这个问题。