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.
Rewriting a cron expression as a systemd timer
Moving a schedule from `cron` to a `systemd` timer means translating the five fields of minute, hour, day of month, month and day of week into the `OnCalendar=` syntax. Enter a cron expression and this tool produces the corresponding `OnCalendar=`, together with warnings about anything that deserves care.
**The most important thing in this translation is how day of month and day of week behave when both are given.** Cron reads the two as an **OR**: `0 0 1 * 1` means "the first of the month **or** every Monday" and may fire some five times a month. **Systemd's `OnCalendar=`, however, treats the same specification as an AND.** It comes to mean "the first **and** a Monday" and fires once or twice a year. **A mechanical translation therefore changes how often the job runs, and does so silently.** This tool detects that combination and warns you about it.
How to convert
- Enter the cron expression Write the five fields — minute, hour, day of month, month, day of week — separated by spaces.
- Review the generated OnCalendar= You are given the corresponding systemd syntax.
- Read the warnings **Where day of month and day of week are both given, the change in meaning is pointed out.**
- Transcribe it into a timer unit Paste it into the `[Timer]` section of a `.timer` file.
Tips for getting more out of it
- 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.
Where it comes in useful
Moving to a container environment
**Containers often carry no cron daemon, so schedules have to move to systemd timers or some other arrangement.**
Wanting a record of what ran
A systemd timer leaves its trace in journald, which can be followed up afterwards.
Wanting dependencies between jobs
**Running only after another unit has started is something cron cannot express.**
Taking stock of existing schedules
Converting a set of cron expressions together gives you the occasion to check that the intervals are what you meant.
Scheduler terms
- Cron expression
- The syntax expressing a time by five fields: minute, hour, day of month, month and day of week. **Day of month and day of week are read as an OR.**
- OnCalendar=
- The key stating the time in a systemd timer. **Day of month and day of week are read as an AND.**
- Timer unit
- A file with the `.timer` extension, which starts the `.service` of the same name.
- Persistent=
- **The setting that makes a timer catch up after boot if the system was down when it should have fired.** It works much as `anacron` does for cron.
- AccuracySec=
- The tolerance on the firing time. A minute of slack applies by default, so state it where the timing must be exact.
- Journald
- Systemd's log collection. The output of a job started by a timer is kept here as well.
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.