systemd定時器→Cron表示式轉換工具

將systemd定時器的OnCalendar=語法轉換為cron表示式(分 時 日 月 星期)的免費工具。是姊妹工具"Cron轉systemd定時器"的逆向轉換。支援daily、weekly等命名快捷方式,並在同時指定日期和星期時給出語義差異警告。

systemd元件與cron欄位對應表

systemd的OnCalendar=語法各部分與cron表示式的5個欄位對應關係如下。

位置 systemd中的對應位置 cron欄位
1 時間部分的分(HH:MM:SS中的MM) 分
2 時間部分的時(HH:MM:SS中的HH) 時
3 日期部分的日(年-月-日中的日) 日(日期)
4 日期部分的月(年-月-日中的月) 月
5 星期字首(例如:Mon、Mon..Fri) 星期

systemd的秒指定(HH:MM:SS中的SS)沒有對應的cron欄位,轉換時會被忽略(若秒不為"00"會顯示警告)。

systemd星期縮寫與cron星期編號對應表

systemd使用英文星期縮寫,而cron使用0~6的數字表示。

systemd星期縮寫 cron星期編號
Sun 0
Mon 1
Tue 2
Wed 3
Thu 4
Fri 5
Sat 6

systemd命名快捷方式與cron表示式對應表

systemd有"daily"、"weekly"等易讀的命名特殊寫法,本工具也支援將它們轉換為cron表示式。

OnCalendar= cron表示式
minutely * * * * *
hourly 0 * * * *
daily 0 0 * * *
weekly 0 0 * * 1
monthly 0 0 1 * *
quarterly 0 0 1 1,4,7,10 *
semiannually 0 0 1 1,7 *
yearly / annually 0 0 1 1 *

常見轉換示例

OnCalendar= cron表示式 含義
*-*-* *:*:00 * * * * * 每分鐘執行一次(相當於cron的"* * * * *")。
*:00/15:00 */15 * * * * 每15分鐘執行一次。
Mon..Fri 09:00:00 0 9 * * 1-5 在工作日(週一至週五)的9點0分執行。
*-*-01 00:00:00 0 0 1 * * 每月1日的0點0分執行。
*-01-01 00:00:00 0 0 1 1 * 每年1月1日的0點0分執行。
Mon *-*-01 00:00:00 0 0 1 * 1 同時指定日期(1日)和星期(週一)的示例。systemd中為AND條件(須同時滿足),但cron中會被解釋為OR條件(滿足其一即可),因此轉換結果的執行頻率會比原OnCalendar表示式更高,請注意。

將日期和星期都限制為非"*"的OnCalendar表示式無法準確轉換為cron表示式(因為systemd是AND條件,而cron是OR條件)。遇到此類情況請務必確認轉換結果的含義。

把 systemd 計時器還原成 cron 式

本工具把 systemd 計時器的 OnCalendar= 還原成「分 時 日 月 星期」的 cron 式,daily、weekly 之類具名的簡寫亦在照應之列。它正是姊妹工具的反向。

這一向的轉換要當心的是:systemd 寫得出的一些東西,cron 表達不來。 OnCalendar= 既能精確到秒、指定年份,也能寫 *-02~03(2月倒數第3天)這樣從月底倒數的日期,而 cron 的五個欄位一樣也容不下。至於 *-*-01..07 這樣的日期區間,cron 也能寫成 1-7,可以直接轉換。至於 Persistent=——停機期間錯過的就在開機後補跑——cron 更是沒有與之相當之物。另一點在於日與星期的語義:systemd 把二者當作與,cron 卻讀作或。 照搬過去,排程便朝著跑得更勤的一側偏了,故本工具在遇到這一情形時會示警。

轉換的步驟

  1. 輸入 OnCalendar= 的取值 形如 Mon *-*-* 06:00:00 可以,daily 之類的名稱亦可。
  2. 查看產生的 cron 式 您會得到對應到五個欄位的結果。
  3. 閱讀警告 cron 表達不來的寫法,以及語義上的分別,都會被點出來。
  4. 謄進 crontab 在其後接上要跑的指令,這一行便可登記了。

用好本工具的小技巧

  • 可以直接輸入"daily"、"weekly"、"monthly"等命名快捷方式,內部會轉換為對應的cron表示式(例如daily會轉換為"0 0 * * *")。
  • 將日期和星期都指定為非"*"時,將systemd的AND條件轉換為cron的OR條件會改變含義。此時請務必確認警告並檢查轉換結果是否符合預期。
  • OnCalendar語法中的年份和秒指定在cron中沒有對應欄位,轉換時會被忽略(會通過警告提示)。
  • 在遷移到Kubernetes CronJob(使用cron格式的排程語法)等場景中,本工具可用於將systemd定時器轉回cron格式。
  • 對於不同時使用星期和日期的簡單排程(每小時、每天、每週等),此轉換始終準確一致。

這些情境會用到

遷往沒有 systemd 的環境

容器與較老的類 UNIX 系統,有時除了 cron 別無他物。

讀懂既有的計時器

縱然對 OnCalendar= 的寫法不熟,化作 cron 式後頻次便一目了然。

讓兩套環境保持同樣的排程

生產跑 systemd、開發跑 cron 時,兩處設定可彼此對照。

盤點自己的排程

一併轉換,正是核對間隔是否合乎本意的好時機。

排程的術語

OnCalendar=
在 systemd 計時器中言明時刻的鍵。星期、日期與時刻可寫在同一行裡。
cron 式
以分、時、日、月、星期五個欄位表示時刻的寫法。它無法精確到秒。
具名簡寫
為常用週期所起的別名,如 daily、weekly、monthly。
語義之別
日與星期同時給出時,systemd 讀作與,cron 讀作或。
Persistent=
把停機期間錯過的執行於開機後補上的設定。cron 沒有與之直接相當之物。
crontab
寫下 cron 排程的那份檔案,或編輯它的那條指令。

常見問題

當遷移到不支援systemd的輕量級Docker容器,或需要在使用cron格式排程語法的Kubernetes CronJob中重現相同的定期執行,或團隊的運維工具只支援cron格式配置時,就需要將現有的systemd定時器配置轉換回cron表示式。

可以。直接輸入"minutely"、"hourly"、"daily"、"weekly"、"monthly"、"yearly"等systemd命名快捷方式,會轉換為對應的cron表示式。

在systemd的OnCalendar語法中,星期指定和日期指定始終是AND條件(須同時滿足)。而在傳統的Vixie cron規範中,若日期和星期都被限制為非"*",則會成為OR條件(滿足其一即可)。因此本工具在檢測到此情況時會顯示警告,提示轉換結果可能比原OnCalendar表示式更寬泛(執行頻率更高)。

由於cron表示式沒有指定年份的欄位,即使OnCalendar表示式中有年份指定(非"*"的值),轉換為cron時也會被忽略。本工具在此情況下會顯示警告,說明轉換結果將不論指定的年份每年都會執行。

本工具涵蓋了姊妹工具cron_to_systemd生成的主要模式(每分鐘、每小時、每天、每週、每月、每年、步進指定、範圍指定、列表指定、星期指定、命名快捷方式),但由於OnCalendar語法比cron表達能力更強,非常複雜的指定(多個年份、秒級的精細重複等)無法用cron準確表示,可能轉換失敗。
工具君

閒話 ― 從systemd定時器"迴歸"cron意味著什麼

技術遷移通常被描述為單向的(從舊機制遷移到新機制),但在實際工作中,反方向的轉換也並不少見。將工作負載從採用systemd的主機環境遷移到只支援cron的輕量級容器,或遷移到採用cron格式排程語法的編排工具(如Kubernetes CronJob)時,就需要將OnCalendar語法轉換回cron表示式。

這種"逆向轉換"之所以不是簡單的一對一對應,是因為systemd的OnCalendar語法比cron表達能力更強,具備年級別指定、秒級精度、日期與星期的AND條件組合等cron的5個欄位無法完全表達的概念。因此本工具的目標是"準確轉換常用的主要模式",對於無法完全覆蓋的複雜指定則作為轉換錯誤處理。

同時指定日期和星期時的語義差異(systemd為AND條件,cron為OR條件)是這種逆向轉換中最大的陷阱。對於"每月1日"且"星期一"這樣的條件,systemd只會鎖定"既是1日又是星期一"的那一天,而cron則會在"是1日的日子"或"是星期一的日子"兩種情況下都執行。本工具明確警告這一點,正是為了讓使用者注意到遷移時容易被忽略的這種含義變化。