Cron Expression to systemd Timer Converter
Free tool to convert a cron expression (minute hour day month weekday) into systemd timer OnCalendar= syntax. Warns about the day-of-month/day-of-week OR-semantics caveat, useful for migrating cron jobs to Docker/Kubernetes environments.
Cron Field to systemd Component Mapping
The 5 fields of a cron expression map to systemd's OnCalendar= syntax as follows.
| Position | Cron field | systemd equivalent |
|---|---|---|
| 1 | Minute | Minute of the time part (MM in HH:MM:SS) |
| 2 | Hour | Hour of the time part (HH in HH:MM:SS) |
| 3 | Day of month | Day of the date part (day in year-month-day) |
| 4 | Month | Month of the date part (month in year-month-day) |
| 5 | Day of week | Weekday prefix (e.g. Mon, Mon..Fri) |
Since cron has no seconds field, the systemd seconds component is always "00". When both day-of-month and month are unrestricted (*), the year-month-day part of systemd can be omitted entirely.
Cron Weekday Number to systemd Weekday Abbreviation
Cron represents weekdays as numbers 0-7, while systemd uses English weekday abbreviations.
| Cron weekday number | systemd weekday abbreviation |
|---|---|
| 0 (7) | Sun |
| 1 | Mon |
| 2 | Tue |
| 3 | Wed |
| 4 | Thu |
| 5 | Fri |
| 6 | Sat |
Common Conversion Examples
| Cron expression | OnCalendar= | Meaning |
|---|---|---|
| * * * * * | OnCalendar=*-*-* *:*:00 | Runs every minute (equivalent to cron's "* * * * *"). |
| */15 * * * * | OnCalendar=*:00/15:00 | Runs every 15 minutes. |
| 0 9 * * 1-5 | OnCalendar=Mon..Fri 09:00:00 | Runs at 9:00 AM on weekdays (Monday through Friday). |
| 0 0 1 * * | OnCalendar=*-*-01 00:00:00 | Runs at midnight on the 1st of every month. |
| 0 0 1 1 * | OnCalendar=*-01-01 00:00:00 | Runs at midnight on January 1st every year. |
| 0 0 1 * 1 | OnCalendar=Mon *-*-01 00:00:00 | An example specifying both day-of-month (the 1st) and day-of-week (Monday). In cron this is an OR condition (runs if either matches), but in systemd it becomes an AND condition (runs only when both match), so the converted result fires less often than the original cron expression. |
A cron expression that restricts both day-of-month and day-of-week (neither is "*") cannot be converted accurately to systemd's OnCalendar syntax, because cron uses OR semantics there while systemd uses AND semantics. Consider splitting such cases into two separate systemd timers.
Tips
- If you restrict both day-of-month and day-of-week to something other than "*", cron's OR condition cannot be represented exactly by systemd's AND condition. Check the warning in the result and consider splitting into two timers if needed.
- Some minimal container base images (e.g. Alpine-based Docker images) don't ship a cron daemon at all, making systemd timers a practical replacement when migrating scheduled jobs.
- You can validate the generated OnCalendar line with the "systemd-analyze calendar" command, which also shows the next scheduled run times.
- Unlike a single crontab line, a systemd timer is made of two files: a .timer unit (the schedule) and a .service unit (the actual job to run).
- For simple schedules that don't combine day-of-month and day-of-week (hourly, daily, weekly, etc.), this conversion is always exact.
Frequently Asked Questions
Side Note — From Cron to systemd Timers
systemd emerged around 2010 as an init system for managing Linux boot processes and has since become the standard on most distributions. Its timer feature provides periodic execution much like cron, but adds capabilities cron never had: dependency resolution, centralized execution logging via journalctl, and configurable retry behavior on failure.
Meanwhile, container environments like Docker and Kubernetes increasingly ship base images without a cron daemon at all, in order to keep image sizes small. When a periodic job needs to run in such environments, the practical options are to rely on an orchestrator-level mechanism such as a Kubernetes CronJob, or to hand it off to systemd timers if the host itself runs systemd.
The OnCalendar= syntax is more expressive than cron's 5 fields — supporting year-level specificity and second-level precision — but that extra expressiveness means some cron expressions (those restricting both day-of-month and day-of-week as an OR condition) change meaning under a naive conversion. This tool surfaces that warning explicitly so migrations don't trip over a pitfall that's easy to miss.