launchd runs program every hour even though StartCalendarInterval array is provided I have my StartCalendarInterval set in my launchd plist file like this:
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
    &lt;dict&gt;
        &lt;key&gt;Label&lt;/key&gt;
        &lt;string&gt;local.script.launcher&lt;/string&gt;
        
        &lt;key&gt;Program&lt;/key&gt;
        &lt;string&gt;/usr/bin/osascript&lt;/string&gt;
        
        &lt;key&gt;ProgramArguments&lt;/key&gt;
        &lt;array&gt;
            &lt;string&gt;osascript&lt;/string&gt;
            &lt;string&gt;/Users/me/basic-script.scpt&lt;/string&gt;
        &lt;/array&gt;
        
        &lt;key&gt;StartCalendarInterval&lt;/key&gt;
        &lt;array&gt;
            &lt;dict&gt;
                &lt;key&gt;Hour&lt;/key&gt;
                &lt;integer&gt;8&lt;/integer&gt;
                &lt;key&gt;Minute&lt;/key&gt;
                &lt;integer&gt;0&lt;/integer&gt;
            &lt;/dict&gt;
            &lt;dict&gt;
                &lt;key&gt;Hour&lt;/key&gt;
                &lt;integer&gt;16&lt;/integer&gt;
                &lt;key&gt;Minute&lt;/key&gt;
                &lt;integer&gt;0&lt;/integer&gt;
            &lt;/dict&gt;
            &lt;dict&gt;
                &lt;key&gt;Hour&lt;/key&gt;
                &lt;integer&gt;24&lt;/integer&gt;
                &lt;key&gt;Minute&lt;/key&gt;
                &lt;integer&gt;0&lt;/integer&gt;
            &lt;/dict&gt;
        &lt;/array&gt;
    &lt;/dict&gt;
&lt;/plist&gt;

Even though I am declaring 3 different StartCalendarIntervals, the agent still launches the program every hour.
What am I doing wrong?
.
SOLUTION:
As per @Phong's answer, for launchd plist files and StartCalendarInterval, midnight, 12AM, or 2400 hours military time is Hour = 0 not 24.
launchd is throwing out 24 as an invalid Hour value, thus interpreting that entire entry as Minute = 0. This causes your agent to run every hour on the dot.

The correct value for midnight is 0:

&lt;dict&gt;
    &lt;key&gt;Hour&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;

    &lt;key&gt;Minute&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
&lt;/dict&gt;