MacOS launchd plist StartInterval and StartCalendarInterval examples

MacOS launchd plist FAQ: Can you share some examples of how to use the MacOS launchd plist file StartInterval and StartCalendarInterval keys?

Sure, here's a quick look at the MacOS launchd StartInterval and StartCalendarInterval keys. These two keys can be used to represent time values in a Mac launchd plist file, and many people have questions about them.

MacOS launchd plist StartInterval examples

The general syntax for the MacOS launchd plist StartInterval key is shown here:

StartInterval <integer>

which, in a launchd plist file, looks like this:

<key>StartInterval</key>
<integer>60</integer>

From Apple's launchd plist man page, the StartInterval key is described like this:

“This optional key causes the job to be started every N seconds. If the system is asleep, the job will be started the next time the computer wakes up. If multiple intervals transpire before the computer is woken, those events will be coalesced into one event upon wake from sleep.”

In English, this means that any job you specify with the "60" second StartInterval shown above will be run about every 60 seconds.

If you have experience with the standard Unix and Linux crontab approach, you would simply put an "*" symbol in the minute's field to represent the "60" seconds shown in the XML above.

MacOS launchd StartCalendarInterval examples

The syntax for the MacOS launchd plist StartCalendarInterval key is shown here:

StartCalendarInterval <dictionary of integers or array of dictionary of integers>

And here is the description of the launchd plist StartCalendarInterval key from from Apple's launchd plist man page:

“This optional key causes the job to be started every calendar interval as specified. Missing arguments are considered to be wildcard. The semantics are much like crontab(5). Unlike cron which skips job invocations when the computer is asleep, launchd will start the job the next time the computer wakes up. If multiple intervals transpire before the computer is woken, those events will be coalesced into one event upon wake from sleep.”

You can specify StartCalendarInterval times using these time keys:

Minute <integer>
The minute on which this job will be run.

Hour <integer>
The hour on which this job will be run.

Day <integer>
The day on which this job will be run.

Weekday <integer>
The weekday on which this job will be run (0 and 7 are Sunday).

Month <integer>
The month on which this job will be run.

Since I learn best by example, I dug around through some sample launchd plist files until I found these StartCalendarInterval examples.

I believe this example means run at the 0th minute of every hour of every day:

<key>StartCalendarInterval</key>
<dict>
  <key>Minute</key>
  <integer>0</integer>
</dict>

This StartCalendarInterval example should mean "run at 3:55" every day, where I think this implies 3:55 am.

<key>StartCalendarInterval</key>
<dict>
  <key>Hour</key>
  <integer>3</integer>
  <key>Minute</key>
  <integer>55</integer>
</dict>

This next StartCalendarInterval example is similar to the previous one, but the job is only run on Day 6 of the week, which should be Saturday.

<key>StartCalendarInterval</key>
<dict>
  <key>Hour</key>
  <integer>3</integer>
  <key>Minute</key>
  <integer>15</integer>
  <key>Weekday</key>
  <integer>6</integer>
</dict>

(Personally, I think if you're going through all this trouble to put this stuff in XML you should be able to use "Sat" or "Saturday" here.)

StartCalendarInterval and running every day of the week

In a related note, this is the approach that seems to be required to run a script or command every day of the work week, Monday through Friday:

  <key>StartCalendarInterval</key>
  <array>
      <!-- SUNDAY (testing) -->
      <dict>
          <key>Weekday</key>
          <integer>0</integer>
          <key>Hour</key>
          <integer>16</integer>
          <key>Minute</key>
          <integer>00</integer>
      </dict>
      <dict>
          <key>Weekday</key>
          <integer>1</integer>
          <key>Hour</key>
          <integer>11</integer>
          <key>Minute</key>
          <integer>0</integer>
      </dict>
      <dict>
          <key>Weekday</key>
          <integer>2</integer>
          <key>Hour</key>
          <integer>11</integer>
          <key>Minute</key>
          <integer>0</integer>
      </dict>
      <dict>
          <key>Weekday</key>
          <integer>3</integer>
          <key>Hour</key>
          <integer>11</integer>
          <key>Minute</key>
          <integer>0</integer>
      </dict>
      <dict>
          <key>Weekday</key>
          <integer>4</integer>
          <key>Hour</key>
          <integer>11</integer>
          <key>Minute</key>
          <integer>0</integer>
      </dict>
      <dict>
          <key>Weekday</key>
          <integer>5</integer>
          <key>Hour</key>
          <integer>11</integer>
          <key>Minute</key>
          <integer>0</integer>
      </dict>
  </array>

While the approach is verbose, I can verify that it works. The first “Sunday” entry is for tests that I ran when I was creating my plist file, and the other entries are for Monday through Friday. Note that the integer value for Sunday is both 0 and 7, so you can use either of those for its Weekday entry.

launchd plist StartInterval and StartCalendarInterval examples - summary

I hope these launchd plist StartInterval and StartCalendarInterval key examples are helpful. As you can see, the StartInterval key is for simple "run every XX seconds", while StartCalendarInterval is used for more complicated timings with launchd jobs. For more information, please see the link to the Apple docs above, or take a look at my Mac startup jobs with launchd plist (instead of cron/crontab) tutorial.