9.1 Calendar Expressions

A timer schedule is a calendar expression in systemd's OnCalendar format. The grammar below is what peinit parses.

DayOfWeek Year-Month-Day Hour:Minute:Second Timezone

Every field is optional, and which fields are present is worked out positionally from their shape.

FieldFormDefault if omitted
DayOfWeekweekday namesany day
DateYear-Month-Day*-*-*
TimeHour:Minute:Second00:00:00
Secondthe :Second of Time:00
Timezonean IANA namesystem-local

A time-only expression such as 02:00:00 implies the date *-*-*. Hour:Minute alone defaults the seconds to 00.

Years range 0–9999, months 1–12, days 1–31.

9.1.1 Component syntax #

Every numeric component, and the weekday, accepts:

  • Wildcard* matches anything.
  • List — comma-separated values: 1,15.
  • Range — two values around .., inclusive: Mon..Fri, 8..17. A reversed range is a parse error rather than a wrap-around.
  • Repetition — a value or range suffixed with / and a step. value/step matches the value and every multiple of the step above it, so 0/15 in the minute field is 0, 15, 30 and 45. start..end/step walks from start to end inclusive.

Weekdays are English names, case-insensitive, abbreviated or full, and accept lists and ranges. Mon and Monday are the same day, as are Tue, Tues and Tuesday.

9.1.2 Last day of the month #

A ~ in place of the - between Month and Day counts the day from the end of the month: ~01 is the last day, ~02 the second-to-last, and so on. *-*~01 is the last day of every month; *-02~03 is the third-to-last day of February.

Repetition combines with it, and steps in the day-of-month direction — which means it walks the offset downwards, towards the end of the month. Mon *-05~07/1 covers the last seven days of May, and combined with Mon resolves to exactly one day: the last Monday in May.

Wildcards, ranges and lists are also accepted after ~, so ~* matches every day and ~03..07 the third- to seventh-to-last.

9.1.3 Named shortcuts #

ShortcutEquivalent
minutely*-*-* *:*:00
hourly*-*-* *:00:00
daily*-*-* 00:00:00
weeklyMon *-*-* 00:00:00
monthly*-*-01 00:00:00
quarterly*-01,04,07,10-01 00:00:00
semiannually*-01,07-01 00:00:00
yearly, annually*-01-01 00:00:00

Shortcut names are case-insensitive and accept a trailing timezone, so daily UTC is valid.

9.1.4 Timezones #

Timezone specifiers are IANA database names — Europe/London, US/Eastern, UTC. An expression with no timezone is interpreted in system-local time.

A name is validated when the expression is parsed and resolved again at evaluation. An unrecognised zone is a hard parse error, not a silent fallback to UTC.

9.1.5 Daylight saving #

  • Spring forward, where the clock skips an hour: a scheduled time falling inside the skipped interval does not fire. peinit moves on to the next scheduled second, then the next date. A schedule of *-03-31 01:30 Europe/London skips 2024 entirely.
  • Fall back, where an hour repeats: a scheduled time inside the repeated interval fires exactly once, on the first occurrence. On re-arming, the same civil time resolves to the same instant, which is not later than the firing that just happened, so the timer advances to the next day rather than firing again.

9.1.6 Precision #

Second-level. Unlike systemd, peinit does not accept fractional seconds — service scheduling has no use for finer granularity, and dropping it keeps the parser simpler. A fraction anywhere in the time component is a parse error.

9.1.7 Examples #

ExpressionMeaning
*-*-* 02:00:00Every day at 2am, system-local.
Mon *-*-* 00:00:00Every Monday at midnight.
*-*-1,15 12:00:00The 1st and 15th, at noon.
*-*~01 00:00:00The last day of each month, at midnight.
Mon..Fri *-*-* 09:00:00Weekdays at 9am.
*-*-* *:00/15:00Every fifteen minutes.
*-*-* 02:00:00 Europe/LondonEvery day at 2am London time.

Edit this page