Quartz.NET Cron Expressions: Complete Guide with Examples

Quartz.NET Cron Expressions: Complete Guide with Examples

If you’ve been using Quartz.NET for background job scheduling, you’ve likely encountered the power and flexibility of cron expressions. They let you describe when a job should run using a compact, human‑readable syntax. Whether you’re new to cron or looking to deepen your understanding, this guide covers everything you need—syntax breakdown, over 20 practical examples, common pitfalls, how to test cron expressions, and a quick comparison with the SimpleTrigger.

Author: QuartzNetPro Team
Published: Wednesday, November 19, 2025


Why Cron Expressions Matter in Quartz.NET

Cron expressions are the backbone of scheduled workflows that need fine‑grained time control—think daily reports, maintenance tasks, or event‑driven triggers. In Quartz.NET, a CronScheduleBuilder turns a string like "0 0 * * * ?" into a trigger that fires at the top of every hour. Mastering cron syntax saves time, reduces errors, and ensures your application behaves exactly as intended.


1. Cron Syntax Explained

A Quartz.NET cron expression consists of six mandatory fields followed by an optional seventh:

Position Field Allowed Values Description
1 Seconds 0-59 Seconds within the minute
2 Minutes 0-59 Minutes within the hour
3 Hours 0-23 Hours within the day
4 Day of Month 1-31 Day of the month
5 Month 1-12 or JAN-DEC Month of the year
6 Day of Week 1-7 or SUN-SAT Day of the week (1=SUN, 7=SAT)
7 Year (optional) 1970-2099 Specific year

Special characters

  • * – all values
  • ? – no specific value (used only in Day of Month or Day of Week)
  • - – range (e.g., 1-5)
  • , – list (e.g., MON,WED,FRI)
  • / – increment (e.g., */15 means every 15 units)
  • L – last (e.g., L in day‑of‑month means last day)
  • W – weekday (e.g., 15W is the nearest weekday to the 15th)
  • # – nth day of the week (e.g., 3#2 is the second Wednesday)

Important: Either Day of Month or Day of Week must be ? (not both can be specific values).


2. 20+ Practical Cron Trigger Examples

Below is a cheat‑sheet of real‑world cron expressions. Use them as a starting point or adapt them for your own schedules.

# Expression When It Fires Use Case
1 0 0/5 * * * ? Every 5 minutes High‑frequency polling
2 0 0/15 * * * ? Every 15 minutes Periodic cache refresh
3 0 0/30 * * * ? Every 30 minutes Data aggregation
4 0 0 0/1 * * ? Every hour Hourly maintenance
5 0 0 0 1/1 * ? Daily at midnight Daily reports
6 0 0 8 1/1 * ? Daily at 08:00 Morning batch job
7 0 0 17 * * ? Daily at 17:00 Evening cleanup
8 0 30 7 ? * MON-FRI Weekdays at 07:30 Morning startup tasks
9 0 0 12 ? * SUN Every Sunday at noon Weekly status report
10 0 0 12 * * ? Daily at noon Lunch‑break reminder
11 0 0 9-17 ? * MON-FRI Every hour 9am-5pm weekdays Real‑time monitoring
12 0 0 0 1 * ? First day of month at midnight Monthly invoicing
13 0 0 0 L * ? Last day of month at midnight Month‑end batch
14 0 0 0 ? * MON Every Monday at midnight Weekly backups
15 0 0 0/6 ? * * Every 6 hours Periodic health checks
16 0 0 0-23/2 ? * * Every 2 hours Data sync
17 0 0 12 15 * ? 15th of each month at noon Mid‑month report
18 0 0 8-17 * * ? Hourly from 8am-5pm daily Business‑hours batch
19 0 0 6-22/3 * * ? Every 3 hours from 6am to 10pm Peak‑time processing
20 0 0 0 ? * MON-FRI Every weekday at midnight Weekday overnight jobs
21 0 0 0 ? * * 2026 Every day at midnight in 2026 Year-specific processing
22 0 0 12 1 1 ? January 1st at noon New Year kickoff

Tip: Always test your expressions before deploying to production.


3. Common Mistakes and How to Avoid Them

Mistake Why It Happens Fix
Using * in both Day‑of‑Month and Day‑of‑Week Quartz requires one to be ? Replace one field with ?
Specifying both day fields Cannot use both simultaneously One must be ?
Misunderstanding L and W They’re only for day‑of‑month Use L for last day, W for nearest weekday
Forgetting the seconds field Quartz.NET requires all 6 fields Always include seconds (use 0 if not needed)
Mixing “/” and “-” incorrectly Conflicts in ranges Keep ranges separate from increments
Using - without proper start < end Invalid range Ensure start <= end
Mis‑typed month abbreviations Quartz is case‑sensitive Use upper‑case JANDEC
Using ? in non‑day fields Only valid for day fields Use * for other fields
Incorrect day-of-week numbering Confusion about 0 vs 1 for Sunday Use 1=SUN through 7=SAT or names

4. Testing Cron Expressions

Quartz.NET ships with a lightweight CronExpression parser. The easiest way to verify a schedule is by using the Cron Expression Tester on our website or via the sample code below:

using Quartz;
using Quartz.Impl;
using System;

var scheduler = await StdSchedulerFactory.GetDefaultScheduler();
var expr = "0 0 12 1/1 * ?";
var cronTrigger = TriggerBuilder.Create()
    .WithCronSchedule(expr)
    .Build();

Console.WriteLine($"Cron: {expr}");
Console.WriteLine($"Next Fire: {cronTrigger.GetFireTimeAfter(DateTimeOffset.UtcNow)}");

Running this snippet in a console app prints the next fire time, helping you confirm the schedule matches your expectations.

For more complex testing, try our Cron Expression Tester widget where you can paste an expression and see a visual timeline.


5. Cron vs SimpleTrigger

  • CronTrigger

    • Supports complex schedules via 6/7 fields.
    • Good for recurring patterns (e.g., “every Tuesday at 14:30”).
    • Requires correct syntax; a single typo can cause job misfires.
  • SimpleTrigger

    • Uses RepeatCount and RepeatInterval.
    • Ideal for fixed‑interval jobs like “run every 5 minutes”.
    • Simpler to configure programmatically.

When to choose which?
If your schedule is time‑based (fixed times, days, or months), use CronTrigger.
For interval‑based tasks that just need to fire after a certain duration, use SimpleTrigger.

Example of a SimpleTrigger that fires every 5 minutes:

var simpleTrigger = TriggerBuilder.Create()
    .WithSimpleSchedule(x => x
        .WithIntervalInMinutes(5)
        .RepeatForever())
    .Build();

6. Using Cron Expressions in Production with QuartzNetPro

When you need enterprise‑grade reliability, our QuartzNetPro module adds:

  • Misfire handling policies to avoid job loss.
  • Time‑zone awareness so jobs respect local time even in distributed clusters.
  • Optimized job stores for high‑volume cron jobs without heap bloat.
var trigger = TriggerBuilder.Create()
    .WithIdentity("myTrigger")
    .WithCronSchedule("0 0 12 * * ?", x => x
        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")))
    .Build();

This configuration guarantees your job fires at noon PST every day, regardless of daylight savings shifts.


Takeaway

  • Master the six mandatory fields and the optional year field.
  • Use our cheat‑sheet as a starting point for any recurring schedule.
  • Double‑check common pitfalls before deploying.
  • Test expressions with the built‑in parser or our online widget.
  • Choose CronTrigger for complex, time‑specific schedules; choose SimpleTrigger for simple intervals.