RecurrenceRule Class

Represents a recurrence rule as defined in RFC 5545 for recurring events.

public abstract class RecurrenceRule : IRecurrenceRule

Remarks

Supports the following RFC 5545 recurrence rule properties:

  • FREQ (Secondly, Minutely, Hourly, Daily, Weekly, Monthly, Yearly)
  • INTERVAL - The interval between occurrences
  • COUNT - Maximum number of occurrences
  • UNTIL - End date for the recurrence
  • WKST - The day on which the workweek starts
  • BYSECOND - Limits occurrences to specific seconds (0-60; 60 denotes a leap second and is normalized to 59)
  • BYMINUTE - Limits occurrences to specific minutes (0-59)
  • BYHOUR - Limits occurrences to specific hours (0-23)
  • BYDAY - Limits occurrences to specific days of the week
  • BYMONTHDAY - Limits occurrences to specific days of the month (1-31, -1 to -31), not when FREQ is WEEKLY
  • BYYEARDAY - Limits occurrences to specific days of the year (1-366, -1 to -366), not when FREQ is DAILY, WEEKLY or MONTHLY
  • BYWEEKNO - Limits occurrences to specific weeks of the year (1-53, -1 to -53), only when FREQ is YEARLY
  • BYMONTH - Limits occurrences to specific months (1-12)
  • BYSETPOS - Limits occurrences to specific positions in the recurrence set (1-366, -1 to -366), only with another BYxxx rule part
  • RSCALE and SKIP (RFC 7529) - Only their GREGORIAN and OMIT values, which are the default behavior

An RFC 2445 extension rule part, whose name starts with X-, is kept in RecurrenceRule.Text and ignored by the evaluation. Any other unknown rule part makes the rule invalid.

The start date of the enumeration is the DTSTART of the recurrence: COUNT and INTERVAL are counted from it.

Example

var rrule = RecurrenceRule.Parse("FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1");
var dtStart = new DateTime(2000, 01, 01, 09, 00, 00);
var occurrences = rrule.GetNextOccurrences(dtStart).Take(50).ToArray();

// Every day of January 2000, until the UNTIL date
Assert.HasCount(31, occurrences);
Assert.Equal(new DateTime(2000, 01, 01, 09, 00, 00), occurrences[0]);
Assert.Equal(new DateTime(2000, 01, 31, 09, 00, 00), occurrences[30]);
Implements

Constructors

NameDescription
RecurrenceRule()

RecurrenceRule()

RecurrenceRule.cs
protected RecurrenceRule()

No documentation is available.

Properties

NameDescription
ByHoursLimits occurrences to specific hours (0-23).
ByMinutesLimits occurrences to specific minutes (0-59).
ByMonthDaysLimits occurrences to specific days of the month (1-31, -1 to -31). It cannot be used when the frequency is weekly.
ByMonthsLimits occurrences to specific months (1-12).
BySecondsLimits occurrences to specific seconds (0-59). A BYSECOND value of 60 denotes a leap second, which DateTime cannot represent, and is normalized to 59.
BySetPositionsLimits occurrences to specific positions in the recurrence set (1-366, -1 to -366). It can only be used with another BYxxx rule part.
EndDateEnd date (inclusive)
IntervalThe interval between occurrences. Must be greater than or equal to 1.
IsForeverGets a value indicating whether the recurrence rule never ends.
OccurrencesThe number of occurrences before the recurrence ends.
TextGets the RFC 5545 string representation of this recurrence rule.
WeekStartThe first day of the week for the recurrence rule.

Limits occurrences to specific hours (0-23).

public IList<int>? ByHours { get; set; }

Property value

IList<int>?

Remarks

The values are validated when the occurrences are enumerated.

Limits occurrences to specific minutes (0-59).

public IList<int>? ByMinutes { get; set; }

Property value

IList<int>?

Remarks

The values are validated when the occurrences are enumerated.

Limits occurrences to specific days of the month (1-31, -1 to -31). It cannot be used when the frequency is weekly.

public IList<int> ByMonthDays { get; set; }

Property value

IList<int>

Remarks

The values are validated when the occurrences are enumerated.

Limits occurrences to specific months (1-12).

public IList<int> ByMonths { get; set; }

Property value

IList<int>

Remarks

The values are validated when the occurrences are enumerated.

Limits occurrences to specific seconds (0-59). A BYSECOND value of 60 denotes a leap second, which DateTime cannot represent, and is normalized to 59.

public IList<int>? BySeconds { get; set; }

Property value

IList<int>?

Remarks

The values are validated when the occurrences are enumerated.

BySetPositions

RecurrenceRule.cs

Limits occurrences to specific positions in the recurrence set (1-366, -1 to -366). It can only be used with another BYxxx rule part.

public IList<int>? BySetPositions { get; set; }

Property value

IList<int>?

Remarks

The values are validated when the occurrences are enumerated.

End date (inclusive)

public DateTime? EndDate { get; set; }

Property value

DateTime?

Exceptions

InvalidOperationException
The value is not null and RecurrenceRule.Occurrences is set.

Remarks

A DateTimeKind.Utc or DateTimeKind.Local value denotes an instant, and a DateTimeKind.Unspecified value a wall-clock reading. Parsing a UTC UNTIL, or one carrying an offset, produces a DateTimeKind.Utc value; a floating date-time or a date produces an DateTimeKind.Unspecified value, a date being stored as its first instant.

An instant bounds the occurrences generated from a DateTimeKind.Utc or DateTimeKind.Local start date, or from a DateTimeOffset, by instant, and a wall-clock reading bounds every occurrence by wall clock.

A parsed date designates the whole day, so it keeps every occurrence on that day, whatever its time. Setting this property stores a date-time. UNTIL has a precision of one second, so a date-time bounds the occurrences at that precision: an occurrence within the second of the value, such as one taking the fractional second of the start date, is kept.

UNTIL and COUNT cannot be used in the same recurrence rule, so RecurrenceRule.Occurrences must be null to set a value.

The interval between occurrences. Must be greater than or equal to 1.

public int Interval { get; set; }

Property value

int

Exceptions

ArgumentOutOfRangeException
The value is less than 1.

Gets a value indicating whether the recurrence rule never ends.

public bool IsForever { get; }

Property value

bool

The number of occurrences before the recurrence ends.

public int? Occurrences { get; set; }

Property value

int?

Exceptions

ArgumentOutOfRangeException
The value is negative.
InvalidOperationException
The value is not null and RecurrenceRule.EndDate is set.

Remarks

UNTIL and COUNT cannot be used in the same recurrence rule, so RecurrenceRule.EndDate must be null to set a value.

Text

Gets the RFC 5545 string representation of this recurrence rule.

public abstract string Text { get; }

Property value

string

The first day of the week for the recurrence rule.

public DayOfWeek WeekStart { get; set; }

Property value

DayOfWeek

Exceptions

ArgumentOutOfRangeException
The value is not a day of the week.

Methods

NameDescription
GetNextOccurrences(DateTime)Gets all occurrences of the recurrence starting from the specified date.
GetNextOccurrences(DateTime, TimeZoneInfo)Gets all occurrences of the recurrence, reading startDate as a wall-clock time in timeZone.
GetNextOccurrences(DateTimeOffset, TimeZoneInfo)Gets all occurrences of the recurrence, starting from the instant startDate denotes.
GetNextOccurrencesInternal(DateTime)When implemented in a derived class, generates the internal sequence of occurrence dates.
Parse(ReadOnlySpan<char>)Parses a recurrence rule string according to RFC 5545 format.
Parse(string)Parses a recurrence rule string according to RFC 5545 format.
ToString()Returns a string that represents the current object.
TryParse(ReadOnlySpan<char>, RecurrenceRule?)Attempts to parse a recurrence rule string.
TryParse(ReadOnlySpan<char>, RecurrenceRule?, string?)Attempts to parse a recurrence rule string.
TryParse(string?, RecurrenceRule?)Attempts to parse a recurrence rule string.
TryParse(string?, RecurrenceRule?, string?)Attempts to parse a recurrence rule string.

GetNextOccurrences overloads

GetNextOccurrences(DateTime)

RecurrenceRule.cs

Gets all occurrences of the recurrence starting from the specified date.

public virtual IEnumerable<DateTime> GetNextOccurrences(DateTime startDate)
Parameters
startDate DateTime
The start of the recurrence, as the DTSTART of an iCalendar event.
Returns

IEnumerable<DateTime> An enumerable sequence of occurrence dates.

Exceptions
InvalidOperationException
A rule part holds a value that RFC 5545 does not allow, such as a RecurrenceRule.ByHours value of 24. It is thrown when the enumeration starts.
Remarks

startDate is the start of the recurrence, not the instant to search from: COUNT counts the occurrences from it, and INTERVAL is aligned on it. To get the occurrences of a series on or after another date, enumerate from the start of the series and skip the earlier occurrences.

A rule cannot express a fraction of a second, so every occurrence takes the fractional second of startDate, as it takes the other time components the rule does not specify.

GetNextOccurrences(DateTime, TimeZoneInfo)

RecurrenceRule.cs

Gets all occurrences of the recurrence, reading startDate as a wall-clock time in timeZone.

public virtual IEnumerable<DateTimeOffset> GetNextOccurrences(DateTime startDate, TimeZoneInfo timeZone)
Parameters
startDate DateTime
The wall-clock time to start generating occurrences from. Its DateTime.Kind is ignored.
timeZone TimeZoneInfo
The time zone the recurrence is expressed in, as an iCalendar DTSTART;TZID= would.
Returns

IEnumerable<DateTimeOffset> An enumerable sequence of occurrences, each carrying the UTC offset in effect at that occurrence.

Exceptions
ArgumentNullException
timeZone is null.
InvalidOperationException
A rule part holds a value that RFC 5545 does not allow, such as a RecurrenceRule.ByHours value of 24. It is thrown when the enumeration starts.
Remarks

The occurrences keep their wall-clock time across a daylight saving transition, so their UTC offset changes. A local time made invalid or ambiguous by a transition is resolved as RFC 5545 section 3.3.5 requires: an ambiguous time keeps its first occurrence, and an invalid time is read with the UTC offset in effect before the gap.

A time inside the gap of a forward transition therefore moves forward by the length of the gap, which can place its instance after the instances of the times that follow it: the occurrences are still returned in increasing order. An instance that denotes the same instant as another one, as the hour skipped by a forward transition does for an hourly recurrence, is ignored as RFC 5545 section 3.8.5.3 requires. COUNT counts the instances in the order the recurrence generates their wall-clock times, and a duplicate does not count again. Across a backward transition, the instants of the repeated hour are skipped.

An occurrence outside the range of DateTimeOffset is not returned: the enumeration ends at the first one after the range.

GetNextOccurrences(DateTimeOffset, TimeZoneInfo)

RecurrenceRule.cs

Gets all occurrences of the recurrence, starting from the instant startDate denotes.

public IEnumerable<DateTimeOffset> GetNextOccurrences(DateTimeOffset startDate, TimeZoneInfo timeZone)
Parameters
startDate DateTimeOffset
The instant to start generating occurrences from. It is reduced to a wall-clock time in timeZone.
timeZone TimeZoneInfo
The time zone the recurrence is expressed in, as an iCalendar DTSTART;TZID= would.
Returns

IEnumerable<DateTimeOffset> An enumerable sequence of occurrences, each carrying the UTC offset in effect at that occurrence.

Exceptions
ArgumentNullException
timeZone is null.
Remarks

The recurrence starts at the wall-clock reading of startDate, as it would with a DTSTART;TZID= holding that reading, but no occurrence before startDate is returned.

Reducing an instant to a wall-clock time is lossy in the hour repeated by a backward transition, where both readings denote the same wall clock and RFC 5545 section 3.3.5 means the first one. When startDate is the second one, the instances of the repeated hour denote instants before it and are not returned, although they still count towards COUNT. Use the DateTime overload to start from the first reading.

GetNextOccurrencesInternal(DateTime)

When implemented in a derived class, generates the internal sequence of occurrence dates.

protected abstract IEnumerable<DateTime> GetNextOccurrencesInternal(DateTime startDate)

Parameters

startDate DateTime
The date to start generating occurrences from.

Returns

IEnumerable<DateTime> An enumerable sequence of occurrence dates.

Parse overloads

Parse(ReadOnlySpan<char>)

RecurrenceRule.cs

Parses a recurrence rule string according to RFC 5545 format.

public static RecurrenceRule Parse(ReadOnlySpan<char> rrule)
Parameters
rrule ReadOnlySpan<char>
The recurrence rule string to parse.
Returns

RecurrenceRule A RecurrenceRule instance representing the parsed rule.

Exceptions
FormatException
Thrown when the recurrence rule format is invalid.

Parse(string)

RecurrenceRule.cs

Parses a recurrence rule string according to RFC 5545 format.

public static RecurrenceRule Parse(string rrule)
Parameters
rrule string
The recurrence rule string to parse.
Returns

RecurrenceRule A RecurrenceRule instance representing the parsed rule.

Exceptions
FormatException
Thrown when the recurrence rule format is invalid.
ArgumentNullException
rrule is null.

Returns a string that represents the current object.

public override string ToString()

Returns

string A string that represents the current object.

TryParse overloads

TryParse(ReadOnlySpan<char>, RecurrenceRule?)

RecurrenceRule.cs

Attempts to parse a recurrence rule string.

public static bool TryParse(ReadOnlySpan<char> rrule, out RecurrenceRule? recurrenceRule)
Parameters
rrule ReadOnlySpan<char>
The recurrence rule string to parse.
recurrenceRule RecurrenceRule?
When successful, contains the parsed recurrence rule.
Returns

bool true if parsing succeeded; otherwise, false.

TryParse(ReadOnlySpan<char>, RecurrenceRule?, string?)

RecurrenceRule.cs

Attempts to parse a recurrence rule string.

public static bool TryParse(ReadOnlySpan<char> rrule, out RecurrenceRule? recurrenceRule, out string? error)
Parameters
rrule ReadOnlySpan<char>
The recurrence rule string to parse.
recurrenceRule RecurrenceRule?
When successful, contains the parsed recurrence rule.
error string?
When parsing fails, contains the error message.
Returns

bool true if parsing succeeded; otherwise, false.

TryParse(string?, RecurrenceRule?)

RecurrenceRule.cs

Attempts to parse a recurrence rule string.

public static bool TryParse(string? rrule, out RecurrenceRule? recurrenceRule)
Parameters
rrule string?
The recurrence rule string to parse.
recurrenceRule RecurrenceRule?
When successful, contains the parsed recurrence rule.
Returns

bool true if parsing succeeded; otherwise, false.

TryParse(string?, RecurrenceRule?, string?)

RecurrenceRule.cs

Attempts to parse a recurrence rule string.

public static bool TryParse(string? rrule, out RecurrenceRule? recurrenceRule, out string? error)
Parameters
rrule string?
The recurrence rule string to parse.
recurrenceRule RecurrenceRule?
When successful, contains the parsed recurrence rule.
error string?
When parsing fails, contains the error message.
Returns

bool true if parsing succeeded; otherwise, false.

Fields

NameDescription
DefaultFirstDayOfWeekThe default first day of the week (Monday).

DefaultFirstDayOfWeek

The default first day of the week (Monday).

public static readonly DayOfWeek DefaultFirstDayOfWeek

Constants

NameDescription
DefaultFirstDayOfWeekStringThe string representation of the default first day of the week.

DefaultFirstDayOfWeekString

The string representation of the default first day of the week.

public const string DefaultFirstDayOfWeekString = "MO"