Quartz.NETQuartz.NET
Home
Features
Blog
Discussions
NuGet
GitHub
Home
Features
Blog
Discussions
NuGet
GitHub
  • Getting Started

    • Overview
    • Quartz 4 Quick Start
    • Tutorial
      • Using Quartz
      • Jobs And Triggers
      • More About Jobs & JobDetails
      • Job Data
      • More About Triggers
      • Querying Jobs and Triggers
      • Simple Triggers
      • Cron Triggers
      • RecurrenceTrigger
      • Time and TimeProvider
      • Trigger and Job Listeners
      • Scheduler Listeners
      • Job Execution Middleware
      • Job Stores
      • Configuration, Resource Usage and Building a Scheduler
      • Building a Scheduler Without a Host
      • Clustering
      • Execution Groups
      • Node Affinity (Preferred Node)
      • Testing
      • Compile-Time Checks
      • Declaring Jobs with Attributes
      • Delegate Jobs
    • Configuration Reference
    • JSON Configuration
    • Cron Expression Reference
    • Multi-Tenancy
    • Comparison
    • Frequently Asked Questions
    • Best Practices
    • Before You Go Live
    • Operating a Cluster
    • Log Events
    • Tenancy Patterns
    • Database Schema
    • Database Schema Changes
    • Migration Guide
    • Troubleshooting
    • API Documentation
  • How To's
    • One-Off Job
    • Rescheduling Jobs
    • Backfill
    • Retrying Failed Jobs
    • Pausing with a Reason
    • Job Continuations
    • Overlap Policy
    • Progress and Execution Logs
    • Job Outcomes
    • Multiple Triggers
    • Job Template
    • Running Quartz under Aspire
    • Quartz.NET with Wolverine
    • Coming from Hangfire
    • Coming from TickerQ
    • Embedding Quartz in a Library
    • Running under an External Leader Election
    • Publishing Trimmed and Native AOT
    • Extending Quartz: what is open, what is closed, and how to ask
    • A Job Store of Your Own
    • A Driver Delegate for a New Database
    • Persisting a Custom Trigger Type
    • A Lock Handler of Your Own
  • Packages

    • Quartz Core Additions

      • Jobs
      • Serialization (System.Text.Json)
      • JSON Serialization
      • Plugins
    • Integrations

      • Aspire Integration
      • ASP.NET Core Integration
      • HTTP API
      • HTTP Client
      • Dashboard
      • Hosted Services Integration
      • Microsoft DI Integration
      • Multiple Schedulers with Microsoft DI
      • Observability
      • Redis Lock Handler
      • TimeZoneConverter Integration
      • Weasel Schema Management
    • 3rd Party Plugins for Quartz
  • Quartz 3.x

    • Getting Started

      • Quartz 3 Quick Start
      • Tutorial
        • Using Quartz
        • Library Overview
        • Jobs And Triggers
        • More About Jobs
        • More About Triggers
        • Execution Groups
        • Node Affinity (Preferred Node)
        • Simple Triggers
        • Cron Triggers
        • RecurrenceTrigger
        • Trigger and Job Listeners
        • Scheduler Listeners
        • Job Stores
        • Tuning the Scheduler
        • Configuration, Resource Usage and SchedulerFactory
        • Advanced (Enterprise) Features
      • Configuration Reference
      • JSON Configuration
      • Multi-Tenancy
      • Frequently Asked Questions
      • Best Practices
      • Tenancy Patterns
      • Troubleshooting
      • API Documentation
      • Database Schema
      • Database Schema Changes
      • Migration Guide
      • Miscellaneous Features
    • How To's

      • One-Off Job
      • Multiple Triggers
      • Job Template
      • Using the CronTrigger
      • Rescheduling Jobs
    • Packages

      • Quartz Core Additions

        • Dashboard
        • Jobs
        • Serialization (System.Text.Json)
        • Serialization (Newtonsoft Json.NET)
        • Plugins
      • Integrations

        • ASP.NET Core Integration
        • Hosted Services Integration
        • Microsoft DI Integration
        • Multiple Schedulers with Microsoft DI
        • OpenTelemetry Integration
        • OpenTracing Integration
        • Redis Lock Handler
        • TimeZoneConverter Integration
      • 3rd Party Plugins for Quartz
  • Old Releases

    • Quartz 2.x
      • Quartz 2 Quick Start
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
        • CronTrigger Tutorial
      • Configuration Reference
      • Migration Guide
      • API Documentation
    • Quartz 1.x
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
      • API Documentation
  • License

Quartz.NET 3.x

These are the documents for the 3.x line, which is maintained. Quartz.NET 4.x is the current release; the migration guide says what changed and what to do about it.

Tips

RecurrenceTrigger is available from Quartz.NET 3.18 onwards.

RecurrenceTrigger schedules with iCalendar RFC 5545 recurrence rules (RRULE). It covers patterns CronTrigger and SimpleTrigger cannot express, such as "every 2nd Monday of the month", "every other week on Monday, Wednesday and Friday", or "the last weekday of March each year". It takes a standard RRULE string and computes fire times lazily, without materializing all occurrences.

RRULE Basics

An RRULE is semicolon-separated key-value pairs. FREQ, the base frequency, is required; the other properties refine the pattern:

PropertyDescriptionExample
FREQBase frequency (required)YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY
INTERVALHow often the recurrence repeats (default: 1)INTERVAL=2 (every other)
COUNTMaximum number of times the trigger will fireCOUNT=10
UNTILEnd date/time for the recurrenceUNTIL=20251231T235959Z
BYDAYDays of the week, optionally with ordinalBYDAY=MO,WE,FR or BYDAY=2MO (2nd Monday)
BYMONTHDAYDays of the month (1-31 or -1 to -31)BYMONTHDAY=15 or BYMONTHDAY=-1 (last day)
BYMONTHMonths of the year (1-12)BYMONTH=1,6,12
BYSETPOSPosition within the expanded setBYSETPOS=-1 (last occurrence)
BYHOURHours (0-23)BYHOUR=9,17
BYMINUTEMinutes (0-59)BYMINUTE=0,30
BYSECONDSeconds (0-59)BYSECOND=0
BYWEEKNOWeek numbers (1-53 or -53 to -1)BYWEEKNO=1,26
BYYEARDAYDay of year (1-366 or -366 to -1)BYYEARDAY=1,100,200
WKSTWeek start day (default: MO)WKST=SU

Tips

COUNT and UNTIL are mutually exclusive in one RRULE.

Warning

COUNT counts actual firings (TimesTriggered), not theoretical occurrences. Misfired occurrences that are skipped (e.g., by the DoNothing misfire policy) do not count; an immediate fire caused by the misfire policy (e.g., FireOnceNow) does. This follows Quartz.NET trigger semantics and differs from strict RFC 5545 occurrence counting.

Examples

Every 2nd Monday of the month at 9:00 AM:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("monthlyTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=MONTHLY;BYDAY=2MO")
    .StartAt(DateBuilder.DateOf(9, 0, 0, 1, 1, 2025))
    .Build();

Every other week on Monday, Wednesday, and Friday:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("weeklyTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR")
    .StartNow()
    .Build();

Last weekday of March each year:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("yearlyTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=YEARLY;BYMONTH=3;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1")
    .StartNow()
    .Build();

Every day, but only on weekdays (skip weekends):

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("weekdayTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR")
    .StartNow()
    .Build();

Last day of every month:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("lastDayTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=MONTHLY;BYMONTHDAY=-1")
    .StartNow()
    .Build();

Every 3 months on the 1st and 15th, limited to 10 occurrences:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("quarterlyTrigger", "group1")
    .WithRecurrenceSchedule("FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=1,15;COUNT=10")
    .StartNow()
    .Build();

Time Zone Support

Recurrence calculations use the system's local time zone unless you set another with the builder's InTimeZone method:

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("trigger1", "group1")
    .WithRecurrenceSchedule("FREQ=MONTHLY;BYDAY=2MO", b => b
        .InTimeZone(Quartz.Util.TimeZoneUtil.FindTimeZoneById("Eastern Standard Time")))
    .StartNow()
    .Build();

DI / Hosted Service Configuration

With AddQuartz(), use WithRecurrenceSchedule on the trigger:

services.AddQuartz(q =>
{
    q.AddJob<MyJob>(j => j.WithIdentity("myJob"));
    q.AddTrigger(t => t
        .ForJob("myJob")
        .WithIdentity("myTrigger")
        .WithRecurrenceSchedule("FREQ=MONTHLY;BYDAY=2MO")
        .StartNow());
});

RecurrenceTrigger Misfire Instructions

Two trigger-specific instructions, with the same semantics as CronTrigger's, plus the generic IgnoreMisfirePolicy:

  • MisfireInstruction.RecurrenceTrigger.FireOnceNow
  • MisfireInstruction.RecurrenceTrigger.DoNothing
  • MisfireInstruction.IgnoreMisfirePolicy

The 'smart policy' instruction (the default) means FireOnceNow.

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("trigger1", "group1")
    .WithRecurrenceSchedule("FREQ=WEEKLY;BYDAY=MO", b => b
        .WithMisfireHandlingInstructionDoNothing())
    .Build();

When to Use RecurrenceTrigger vs Other Triggers

ScenarioRecommended Trigger
Fixed interval (every 10 seconds)SimpleTrigger
Cron-expressible pattern (every weekday at 9am)CronTrigger
Nth day-of-week in month (2nd Monday)RecurrenceTrigger
Last weekday of a monthRecurrenceTrigger
Every other week on specific daysRecurrenceTrigger
Complex yearly patterns with BYSETPOSRecurrenceTrigger
Calendar interval (every 5 months)CalendarIntervalTrigger

Persistence

RecurrenceTrigger is stored in the existing QRTZ_SIMPROP_TRIGGERS table, so no schema change is needed. The RRULE string is in the STR_PROP_1 column (max 512 characters), and the trigger type discriminator is RECUR.

Help us by improving this page!
Last Updated: 9/30/26, 6:00 AM
Contributors: Marko Lahma, Claude Opus 5.5
Prev
Cron Triggers
Next
Trigger and Job Listeners