fixmint
ZH

如何逐个字段读懂 Cron 表达式

作者: · · 阅读约 5 分钟

Cron 表达式是一行简短的文本,用来告诉调度器什么时候运行任务。常见格式有五个字段,用空格分隔:分钟、小时、日期、月份和星期。这一行 0 9 * * 1-5 表示周一到周五的 09:00。每个字段可以是数字、名称、列表、范围或步长,也可以是表示所有值的 *。当所有字段都匹配时,任务才会在那个时刻运行。

Cron表达式解析器Cron任务运行时间不对免费使用

五个字段

字段可用取值示例
分钟0 到 5930 表示每小时的第 30 分钟
小时0 到 239 表示 09:00,采用 24 小时制
日期1 到 3115 表示每月 15 日
月份1 到 12,或 JAN 到 DEC3 或 MAR 表示三月
星期0 到 6,或 SUN 到 SAT0 或 SUN 表示星期日,1 表示星期一

有些系统也接受 7 表示星期日,但并非所有系统都支持,所以建议使用 0 或 SUN。这种格式的 cron 没有秒字段,所以最小的时间单位是一分钟。

列表、范围、步长和名称

  • 表示该字段的所有值。 * * * * 表示每分钟运行一次。
  • 列表用逗号分隔。0 9,17 * * * 表示每天 09:00 和 17:00 运行。
  • 范围用连字符表示。星期字段中的 1-5 表示周一到周五。
  • 步长用斜杠表示。分钟字段中的 */15 表示 0、15、30 和 45 分。10-30/5 表示 10、15、20、25 和 30 分。
  • 名称如 MON-FRI 可以代替数字,更容易读懂,前提是你的调度器支持。

这些写法可以组合使用。0 8-18/2 * * * 表示从 08:00 到 18:00,每隔两小时的第 0 分钟运行。

常见的时间安排

表达式含义
* * * * *每分钟
/15 * * *每 15 分钟
0 * * * *每小时的第 0 分钟
0 2 * * *每天 02:00
0 9 * * 1-5周一到周五的 09:00
0 9,17 * * *每天 09:00 和 17:00
30 6 1 * *每月 1 日 06:30
0 0 * * 0每周日午夜
0 0 1 1 *1 月 1 日午夜
/5 9-17 * 1-5周一到周五,从 09:00 到 17:55 每 5 分钟一次

注意,0 0 * * 是午夜,0 12 * * 是中午。把小时写错是最常见的错误之一。

日期与星期

当日期字段和星期字段都做了限制时,只要其中任意一个匹配,任务就会运行。这是 Vixie cron 以及许多由它衍生的系统所采用的经典规则。因此,0 0 13 * 5 会在每月 13 日的午夜运行,也会在每个星期五运行。很多人以为它只会在"星期五且是 13 日"时运行,结果运行次数比预期多得多。

如果两个字段中有一个是 *,那么只有另一个字段生效。要想只在"星期五的 13 日"运行,可以每周五都安排任务,然后在脚本内部检查日期。其他调度器,包括一些云服务,可能采用不同的规则,使用前请查阅它们的文档。

时区与夏令时

Cron 按照运行它的机器或服务的时钟运行,通常就是该机器所在时区的本地时间。设置为 02:30 的任务,会在该时钟显示 02:30 时运行。先检查时区(在 Linux 上可以用 date 查看)。如果希望任务在各处都按同一个时钟运行,许多团队会把服务器设为 UTC,有些调度器也允许为每个任务单独设置时区。

夏令时每年会调整两次时钟。春季,许多地方的时钟会从 02:00 直接跳到 03:00,因此 02:30 的任务根本没有机会运行。秋季,01:00 到 01:59 这一小时会出现两次。不同的调度器对这些情况的处理方式不同:有的跳过任务,有的只运行一次,有的运行两次。如果差异对你很重要,就避开凌晨的时间调整窗口,或者改用 UTC。

六个字段与 Quartz

一些调度器会在开头增加一个秒字段,所以 /10 * * * * 表示每 10 秒运行一次。Java 的 Quartz 调度器使用秒、分钟、小时、日期、月份、星期以及可选的年份字段,并增加了四个特殊字符:

  • ? 表示"不指定具体值"。Quartz 要求日期字段或星期字段中,必须有一个使用它,具体是哪个取决于你没有设置的那个字段。
  • L 表示最后一个。日期字段中的 L 表示月末最后一天,星期字段中的 6L 表示最后一个星期五。
  • W 表示最近的工作日。15W 是离 15 日最近的工作日,并且不会跨到另一个月。
  • # 表示第 n 个某星期几。6#3 表示第三个星期五。

Quartz 对星期的编号与五字段格式不同。它的 1 表示星期日,7 表示星期六,因此周一到周五应写作 2-6,而不是 1-5。在复制任何一行之前,请先确认你的调度器使用哪种格式。

常见错误

  • 分钟字段写 */7。取值是 0、7、14,一直到 56。下一个值本应是 63,但它超出了范围,所以 56 之后的运行会在下一小时的第 0 分钟。间隔只有四分钟,而且分布不均匀。应使用能被 60 整除的步长,比如 5、10、15 或 30。
  • 2 月 30 日。 这样的日期不存在,所以 0 0 30 2 * 永远不会运行。在只有 30 天的月份里写 31 日也是同样的道理。按照"二者任一"的规则,星期字段的限制仍可能让任务在其他日子运行,所以要检查结果。
  • 小时写 24 或分钟写 60。 这些值超出了范围。大多数调度器在保存时会拒绝,但并非全部都会。
  • 以为有秒。 五字段的表达式只能精确到整分钟。
  • 把 cron 和正则表达式混为一谈。 在 cron 中, 表示所有值;在正则表达式中, 表示重复前面的项目。要测试模式,请使用正则表达式测试工具,并且把 cron 表达式和正则分开看待。

检查接下来的运行时间

在依赖某个时间安排之前,先用白话读一遍这一行,并列出接下来几次的运行时间。Cron 表达式解析器可以同时完成这两件事,这是发现"二者任一"规则或奇怪步长最快的方法。

快速解答

第一个字段是分钟还是秒?

在标准的五字段格式中是分钟。只有部分六字段的调度器会增加秒,并且把秒放在最前面。

为什么我的任务既在星期五运行,又在 13 日运行?

因为日期字段和星期字段都已设置,所以只要其中一个匹配,任务就会运行。如果只想让其中一个生效,就把另一个字段设为 *。

Cron 使用 UTC 吗?

只有当机器或服务被设置为 UTC 时才是。否则,它使用该系统所在的本地时区。

由 AI 辅助翻译自英文原文。

评论

    还没有评论。快来抢沙发。

    你的评分(可选)

    你的邮箱不会被显示或保存。

    Agentic AI in the Browser 的封面Agentic AI in the Browser

    隐私优先、基于浏览器的AI工作流应用案例,体现的是fixmint所依托的“在设备上直接完成”这一理念。

    $4.99在 Gumroad 获取英文阅读