Cron expression for the second Tuesday of the month
At 09:00, on the second Tuesday of the month.
Next 10 runs
In Quartz, worked out in your browser from the current time.
At a glance
- Runs
- 12 in 2027
- Gap between runs
- 28 days to 35 days
- Expressible in
- EventBridge and Quartz and Azure; workarounds for the rest
- Clock changes
- No effect in the zones checked
In each dialect
Every expression here is generated by the tester’s own engine and checked run for run against the others, so “Exact” means the same clock times in the same zone. Each one links to the tester.
Standard cron has no #. Writing 8-14 with the weekday does not work, because cron fires when either field matches.
Workaround
Schedule 0 9 * * 2 (at 09:00, on Tuesdays) and let a shell test go ahead only when the date is between the 8th and the 14th. In a crontab, % must be written \%, or cron cuts the line there.
0 9 * * 2 [ $(date +\%-d) -ge 8 ] && [ $(date +\%-d) -le 14 ] && /path/to/commandaws events put-rule --name second-tuesday-of-month --schedule-expression "cron(0 9 ? * 3#2 *)"- Wrap it in
cron(…). Day of week is set (3#2), so day of month has to be?. The final*is the required year field. - Scheduled rules always run in UTC. For local times, create it in EventBridge Scheduler with
--schedule-expression-timezone.
CronScheduleBuilder.cronSchedule("0 0 9 ? * 3#2")- The leading
0is the seconds field, so it fires at the top of the minute. Day of week is set (3#2), so day of month has to be?. The optional year is left off. - Uses the JVM’s default zone unless the trigger sets one with
inTimeZone.
Kubernetes CronJob has no #. Writing 8-14 with the weekday does not work, because cron fires when either field matches.
Workaround
Schedule 0 9 * * 2 and put the test in front of the container’s command, so the Job exits straight away unless the date is between the 8th and the 14th. The test uses GNU date, so Alpine and other BusyBox images need coreutils. The container’s clock is UTC unless you set TZ; match it to timeZone.
schedule: "0 9 * * 2"
# in the container:
command: ["sh", "-c", "[ $(date +%-d) -ge 8 ] && [ $(date +%-d) -le 14 ] && exec /app/job"]GitHub Actions has no #. Writing 8-14 with the weekday does not work, because cron fires when either field matches.
Workaround
Schedule 0 9 * * 2 and make the test the first line of the step that does the work, so the step ends early unless the date is between the 8th and the 14th. The runner’s clock is UTC; if you set timezone, give the step the same zone with env: TZ.
- cron: '0 9 * * 2'
# in the job:
- run: |
[ $(date +%-d) -ge 8 ] && [ $(date +%-d) -le 14 ] || exit 0
./your-script[TimerTrigger("0 0 9 8-14 * Tue")]- Azure requires both day fields to match, so a seven-day window plus the weekday means the same thing.
- Azure’s NCrontab requires both day fields to match. This fires only when the day of month and the day of week agree, which is the opposite of Unix cron.
- Six fields with seconds first, so the leading
0fires at the top of the minute. - Azure numbers days 0–6 from Sunday, like Unix cron, and matches names by prefix, so keep to three letters.
- UTC unless the app sets
WEBSITE_TIME_ZONE, which Linux Consumption and Flex Consumption plans do not support.
About this schedule
The day Microsoft ships its monthly security updates, often called Patch Tuesday. The second Tuesday always falls on the 8th to the 14th, which is why Azure can express it with a date range and a weekday together.
Clock changes
None of these times falls in the hour that clocks skip or repeat in New York, London, Berlin, Helsinki or Sydney, so every dialect runs it normally all year there. Zones that change clocks at other hours can still differ.
Questions
- What is the cron expression for the second Tuesday of the month?
- It is
0 9 ? * 3#2 *in EventBridge,0 0 9 ? * 3#2in Quartz and0 0 9 8-14 * Tuein Azure. Standard cron, Kubernetes and GitHub Actions cannot express it in one line, so this page gives a tested workaround for each. - Can a Kubernetes CronJob run on the second Tuesday of the month?
- Not with the schedule alone. Schedule
0 9 * * 2and put the test in front of the container’s command, so the Job exits straight away unless the date is between the 8th and the 14th. The test uses GNUdate, so Alpine and other BusyBox images needcoreutils. The container’s clock is UTC unless you setTZ; match it totimeZone.