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

    • Quartz 3 Quick Start
    • Tutorial
      • Using Quartz
      • Library Overview
      • Jobs And Triggers
      • More About Jobs
      • More About Triggers
      • 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
    • Frequently Asked Questions
    • Best Practices
    • Troubleshooting
    • API Documentation
    • Database Schema
    • 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
  • Unreleased Releases

    • Quartz 4.x
      • Quartz 4 Quick Start
      • Tutorial
        • Using Quartz
        • Jobs And Triggers
        • More About Jobs & JobDetails
        • More About Triggers
        • Simple Triggers
        • Cron Triggers
        • RecurrenceTrigger
        • Trigger and Job Listeners
        • Scheduler Listeners
        • Job Stores
        • Configuration, Resource Usage and SchedulerFactory
        • Advanced (Enterprise) Features
        • Miscellaneous Features
        • CronTrigger Tutorial
      • Configuration Reference
      • Migration Guide
      • Troubleshooting
      • API Documentation
      • How To's

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

        • Quartz Core Additions

          • Dashboard
          • Jobs
          • JSON Serialization
          • Plugins
        • Integrations

          • ASP.NET Core Integration
          • HTTP API
          • 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

Tips

RecurrenceTrigger is available from Quartz.NET 3.18 onwards.

RecurrenceTrigger uses iCalendar RFC 5545 recurrence rules (RRULE) to define schedules. This trigger type enables complex scheduling patterns that cannot be expressed with CronTrigger or SimpleTrigger, such as "every 2nd Monday of the month", "every other week on Monday, Wednesday and Friday", or "the last weekday of March each year".

RecurrenceTrigger accepts a standard RRULE string and computes fire times lazily without materializing all occurrences.

RRULE Basics

An RRULE string defines a recurrence pattern using semicolon-separated key-value pairs. The FREQ property is required and specifies the base frequency. 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 - you cannot use both in the same RRULE.

Warning

COUNT tracks the number of times the trigger has actually fired (via TimesTriggered), not the number of theoretical recurrence occurrences. Misfired occurrences that are skipped (e.g., via DoNothing misfire policy) do not count toward the limit. However, if the misfire policy causes an immediate fire (e.g., FireOnceNow), that fire does count. This is consistent with Quartz.NET trigger semantics but 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

By default, recurrence calculations use the system's local time zone. You can specify a different time zone using 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

When using AddQuartz() for dependency injection, configure a recurrence trigger with WithRecurrenceSchedule:

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

RecurrenceTrigger has two trigger-specific misfire instructions (identical semantics to CronTrigger), plus the generic IgnoreMisfirePolicy:

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

If the 'smart policy' instruction is used (the default), RecurrenceTrigger will use 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 uses the existing QRTZ_SIMPROP_TRIGGERS table for persistence - no database schema changes are required. The RRULE string is stored in the STR_PROP_1 column (max 512 characters). The trigger type discriminator is RECUR.

Help us by improving this page!
Last Updated: 4/4/26, 1:40 PM
Contributors: Marko Lahma, Claude Opus 4.6 (1M context)
Prev
Cron Triggers
Next
Trigger and Job Listeners