Cron表达式转systemd定时器工具

免费工具,将cron表达式(分 时 日 月 星期)转换为systemd定时器的OnCalendar=语法。同时对日期与星期同时限定时的OR语义差异进行提示,适用于将cron任务迁移到Docker/Kubernetes环境。

cron字段与systemd组成部分对照表

cron表达式的5个字段与systemd的OnCalendar=语法对应关系如下。

位置 cron字段 systemd对应部分
1 分钟 时间部分的分钟(HH:MM:SS中的MM)
2 小时 时间部分的小时(HH:MM:SS中的HH)
3 日(日期) 日期部分的日(年-月-日中的日)
4 日期部分的月(年-月-日中的月)
5 星期 星期前缀(例如Mon、Mon..Fri)

由于cron没有秒字段,systemd的秒部分始终为"00"。当日期和月份均不受限(*)时,systemd的年-月-日部分可以完全省略。

cron星期编号与systemd星期缩写对照表

cron用0〜7的数字表示星期,而systemd使用英文星期缩写。

cron星期编号 systemd星期缩写
0 (7) Sun
1 Mon
2 Tue
3 Wed
4 Thu
5 Fri
6 Sat

常见转换示例

cron表达式 OnCalendar= 含义
* * * * * OnCalendar=*-*-* *:*:00 每分钟执行一次(相当于cron的"* * * * *")。
*/15 * * * * OnCalendar=*:00/15:00 每15分钟执行一次。
0 9 * * 1-5 OnCalendar=Mon..Fri 09:00:00 工作日(周一至周五)上午9点执行。
0 0 1 * * OnCalendar=*-*-01 00:00:00 每月1日0点执行。
0 0 1 1 * OnCalendar=*-01-01 00:00:00 每年1月1日0点执行。
0 0 1 * 1 OnCalendar=Mon *-*-01 00:00:00 同时指定日期(1日)与星期(周一)的示例。在cron中这是OR条件(满足其一即可执行),但在systemd中会变为AND条件(必须同时满足才执行),因此转换结果的执行频率会低于原cron表达式。

同时限定日期与星期(均不为"*")的cron表达式,无法通过systemd的OnCalendar语法准确转换,因为cron在此情形下是OR语义,而systemd始终是AND语义。建议将此类情况拆分为两个独立的systemd定时器。

使用提示

  • 如果将日期与星期都设为非"*",cron的OR条件无法用systemd的AND条件准确表达。请查看转换结果中的警告,必要时拆分为两个定时器。
  • 一些最小化的容器基础镜像(例如基于Alpine的Docker镜像)根本不包含cron守护进程,此时systemd定时器是迁移计划任务的实用替代方案。
  • 可以使用"systemd-analyze calendar"命令验证生成的OnCalendar行,该命令还会显示接下来的计划执行时间。
  • 与单行crontab不同,systemd定时器由两个文件组成:.timer单元(计划部分)和.service单元(实际执行的任务)。
  • 对于不同时组合日期与星期的简单计划(每小时、每天、每周等),本转换结果始终是精确的。

常见问题

OnCalendar=的格式为"星期 年-月-日 时:分:秒"(星期和日期部分可省略)。"*"表示"任意值",".."表示范围,"/"表示间隔,","用于列举多个值。例如"Mon..Fri 09:00:00"表示工作日上午9点整。

systemd定时器提供了cron本身没有的功能:通过journalctl集中管理执行日志、等待依赖的服务先启动、以及可配置的失败自动重试。容器基础镜像也越来越倾向于不包含cron守护进程以保持轻量,因此在基于systemd的主机上,定时器成为自然的替代方案。

按照Vixie cron的语义,当日期与星期都被限定(非"*")时,只要满足其中一个条件任务就会执行,即OR条件。而systemd的OnCalendar语法始终将星期和日期部分作为AND条件处理(必须同时满足)。本工具会检测到这种情况并显示警告,提示转换结果的执行频率可能低于原cron表达式。

对于不同时组合日期与星期的简单计划,转换结果是精确的。但如果出现了OR语义警告,实际执行频率可能与预期不同,建议在部署到生产环境前使用"systemd-analyze calendar"命令确认接下来的计划执行时间。

标准的5字段cron表达式没有秒字段,因此生成的OnCalendar行中的秒部分始终为"00"。systemd的OnCalendar语法本身支持指定秒,但本工具从cron转换时不会使用该功能。
ツールくん

闲话 ― 从cron到systemd定时器

systemd大约于2010年前后作为管理Linux启动流程的初始化系统出现,此后成为大多数发行版的标准配置。其中的定时器功能与cron类似,提供周期性执行能力,但增加了cron从未拥有的功能:依赖关系解析、通过journalctl集中管理执行日志,以及可配置的失败重试行为。

与此同时,Docker和Kubernetes等容器环境中,为了保持镜像体积小巧,越来越多的基础镜像根本不包含cron守护进程。当需要在此类环境中运行周期性任务时,现实的选择要么依赖Kubernetes CronJob等编排层面的机制,要么在主机本身运行systemd的情况下交给systemd定时器处理。

OnCalendar=语法比cron的5个字段表达能力更强,支持指定年份精度和秒级精度,但正因如此,一些cron表达式(同时限定日期与星期的OR条件)在简单转换下会改变含义。本工具明确地提示这一警告,正是为了让迁移过程不至于陷入这个容易被忽略的陷阱。