systemd Timer to Cron Expression Converter

Convert a systemd timer's OnCalendar= syntax to a cron expression (minute hour day month weekday) for free. The reverse of our "Cron to systemd Timer" converter. Supports named shortcuts (daily, weekly, etc.) and warns about semantic differences when day-of-month and weekday are both specified.

systemd component to cron field mapping

Each part of systemd's OnCalendar= syntax maps to one of cron's five fields as follows.

Position Where it appears in systemd Cron field
1 Minute in the time part (MM in HH:MM:SS) Minute
2 Hour in the time part (HH in HH:MM:SS) Hour
3 Day in the date part (day in year-month-day) Day of month
4 Month in the date part (month in year-month-day) Month
5 Weekday prefix (e.g. Mon, Mon..Fri) Day of week

systemd's seconds field (SS in HH:MM:SS) has no cron equivalent, so it's ignored during conversion (a warning appears if seconds is anything other than "00").

systemd weekday abbreviation to cron day-of-week number mapping

systemd uses English weekday abbreviations, while cron uses numbers 0-6.

systemd weekday abbreviation cron day-of-week number
Sun 0
Mon 1
Tue 2
Wed 3
Thu 4
Fri 5
Sat 6

systemd named shortcuts to cron expression mapping

systemd has readable named shortcuts like "daily" and "weekly", and this tool can convert those to cron expressions too.

OnCalendar= Cron expression
minutely * * * * *
hourly 0 * * * *
daily / midnight 0 0 * * *
weekly 0 0 * * 1
monthly 0 0 1 * *
yearly / annually 0 0 1 1 *

Common conversion examples

OnCalendar= Cron expression Meaning
*-*-* *:*:00 * * * * * Runs every minute (equivalent to cron's "* * * * *").
*:00/15:00 */15 * * * * Runs every 15 minutes.
Mon..Fri 09:00:00 0 9 * * 1-5 Runs at 9:00 AM on weekdays (Monday-Friday).
*-*-01 00:00:00 0 0 1 * * Runs at midnight on the 1st of every month.
*-01-01 00:00:00 0 0 1 1 * Runs at midnight on January 1st every year.
Mon *-*-01 00:00:00 0 0 1 * 1 An example specifying both a day of month (the 1st) and a weekday (Monday). systemd treats this as an AND condition (runs only when both match), but cron interprets it as an OR condition (runs when either matches) — so the converted result runs more often than the original OnCalendar expression intended.

An OnCalendar expression that restricts both day-of-month and weekday to something other than "*" cannot be accurately converted to cron (systemd uses AND logic, cron uses OR logic). Always double-check the meaning of the conversion result in cases like this.

Tips

  • You can type named shortcuts like "daily", "weekly", or "monthly" directly — they're converted to the equivalent cron expression internally (e.g. "daily" becomes "0 0 * * *").
  • Restricting both day-of-month and weekday to something other than "*" changes the meaning when converting systemd's AND logic into cron's OR logic. Check the warning in that case and confirm the result matches your intent.
  • OnCalendar's year and seconds fields have no cron equivalent, so they're dropped during conversion (a warning notifies you when this happens).
  • Handy when migrating workloads off systemd — for example, when moving a scheduled job to a Kubernetes CronJob (which uses cron-style syntax).
  • For simple schedules that don't combine weekday and date restrictions (hourly, daily, weekly, etc.), this conversion is always exact.

Frequently asked questions

This comes up when migrating to a lightweight Docker container that doesn't have systemd, when reproducing the same schedule in a Kubernetes CronJob (which uses cron-style syntax), or when your team's tooling only supports cron-format configuration.

Yes. Typing systemd named shortcuts like "minutely", "hourly", "daily", "weekly", "monthly", or "yearly" directly converts them to the equivalent cron expression.

In systemd's OnCalendar syntax, a weekday restriction and a date restriction are always combined with AND logic (both must match). Under classic Vixie cron semantics, though, restricting both day-of-month and weekday to something other than "*" makes them an OR condition (either one matching is enough). This tool detects that case and shows a warning that the converted result may be broader (run more often) than the original OnCalendar expression.

Cron expressions have no field for the year, so any year restriction in an OnCalendar expression (anything other than "*") is ignored during conversion. This tool shows a warning in that case, noting the converted result runs every year regardless of the year you specified.

The tool covers the main patterns our "Cron to systemd Timer" tool generates (per-minute, hourly, daily, weekly, monthly, yearly, step, range, list, weekday restrictions, and named shortcuts). Because OnCalendar syntax is more expressive than cron, though, very complex specifications — multiple years, fine-grained second-level repeats — can't be represented accurately in cron and may fail to convert.
ツールくん

Side Note — What it means to convert a systemd timer back to cron

Technology migrations are usually framed as one-directional — moving from an old mechanism to a newer one — but in practice, the reverse conversion comes up plenty too. Moving a workload from a systemd-based host to a lightweight container that only supports cron, or to an orchestration tool that uses cron-style scheduling syntax (like Kubernetes CronJob), means converting OnCalendar syntax back into a cron expression.

This "reverse conversion" isn't a simple one-to-one mapping, because systemd's OnCalendar syntax is more expressive than cron. It supports concepts cron's five fields simply can't represent — year-level restrictions, second-level precision, and an AND-style combination of date and weekday. That's why this tool aims to accurately convert the commonly used patterns, and treats anything more complex as a conversion error rather than guessing at an approximation.

The semantic difference when both day-of-month and weekday are specified — systemd's AND logic versus cron's OR logic — is the biggest pitfall in this reverse conversion. A condition like "the 1st of the month" AND "Monday" narrows systemd down to only days that are both the 1st and a Monday, but cron would instead run on any day that's either the 1st or a Monday. This tool warns about it explicitly so this easy-to-miss shift in meaning doesn't slip through during a migration.