using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Runtime.InteropServices;
public static void Main()
var helper = new RecurrenceHelper();
var dates = RecurrenceHelper.GetRecurrenceDateTimeCollection("FREQ=YEARLY;COUNT=3;BYMONTH=2;BYDAY=1SU", DateTime.Now);
foreach(var item in dates) {
Console.WriteLine("date:" + item);
public class RecurrenceHelper
internal static List<string> valueList = new List<string>();
internal static string COUNT;
internal static string RECCOUNT;
internal static string DAILY;
internal static string WEEKLY;
internal static string MONTHLY;
internal static string YEARLY;
internal static string INTERVAL;
internal static string INTERVALCOUNT;
internal static string BYSETPOS;
internal static string BYSETPOSCOUNT;
internal static string BYDAY;
internal static string BYDAYVALUE;
internal static string BYMONTHDAY;
internal static string BYMONTHDAYCOUNT;
internal static string BYMONTH;
internal static string BYMONTHCOUNT;
internal static int BYDAYPOSITION;
internal static int BYMONTHDAYPOSITION;
internal static int WEEKLYBYDAYPOS;
internal static string WEEKLYBYDAY;
internal static List<DateTime> exDateList = new List<DateTime>();
internal static Nullable<DateTime> UNTIL;
public static IEnumerable<DateTime> GetRecurrenceDateTimeCollection(string RRule, DateTime RecStartDate)
var filteredDates = GetRecurrenceDateCollection(RRule, RecStartDate, null, 43);
public static IEnumerable<DateTime> GetRecurrenceDateTimeCollection(string RRule, DateTime RecStartDate, int NeverCount)
var filteredDates = GetRecurrenceDateCollection(RRule, RecStartDate, null, NeverCount);
public static IEnumerable<DateTime> GetRecurrenceDateTimeCollection(string RRule, DateTime RecStartDate, string RecException)
var filteredDates = GetRecurrenceDateCollection(RRule, RecStartDate, RecException, 43);
public static IEnumerable<DateTime> GetRecurrenceDateTimeCollection(string RRule, DateTime RecStartDate, string RecException, int NeverCount)
var filteredDates = GetRecurrenceDateCollection(RRule, RecStartDate, RecException, NeverCount);
public static IEnumerable<DateTime> GetRecurrenceDateCollection(string RRule, DateTime RecStartDate, string RecException, int NeverCount)
List<DateTime> RecDateCollection = new List<DateTime>();
DateTime startDate = RecStartDate;
var ruleSeperator = new[] { '=', ';', ',' };
var weeklySeperator = new[] { ';' };
string[] ruleArray = RRule.Split(ruleSeperator);
FindKeyIndex(ruleArray, RecStartDate);
string[] weeklyRule = RRule.Split(weeklySeperator);
FindWeeklyRule(weeklyRule);
if (RecException != null)
FindExdateList(RecException);
if (ruleArray.Length != 0 && RRule != "")
DateTime addDate = startDate;
int.TryParse(RECCOUNT, out recCount);
if ((ruleArray.Length > 4 && INTERVAL == "INTERVAL") || ruleArray.Length == 4)
int DyDayGap = ruleArray.Length == 4 ? 1 : int.Parse(INTERVALCOUNT);
if (recCount == 0 && UNTIL == null)
for (int i = 0; i < recCount; i++)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddDays(DyDayGap);
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddDays(DyDayGap);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
else if (WEEKLY == "WEEKLY")
int WyWeekGap = ruleArray.Length > 4 && INTERVAL == "INTERVAL" ? int.Parse(INTERVALCOUNT) : 1;
bool isweeklyselected = weeklyRule[WEEKLYBYDAYPOS].Length > 6;
if (recCount == 0 && UNTIL == null)
while (RecDateCollection.Count < recCount && isweeklyselected)
GetWeeklyDateCollection(addDate, weeklyRule, RecDateCollection);
addDate = addDate.DayOfWeek == DayOfWeek.Saturday ? addDate.AddDays(((WyWeekGap - 1) * 7) + 1) : addDate.AddDays(1);
bool IsUntilDateReached = false;
while (!IsUntilDateReached && isweeklyselected)
GetWeeklyDateCollection(addDate, weeklyRule, RecDateCollection);
addDate = addDate.DayOfWeek == DayOfWeek.Saturday ? addDate.AddDays(((WyWeekGap - 1) * 7) + 1) : addDate.AddDays(1);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
else if (MONTHLY == "MONTHLY")
int MyMonthGap = ruleArray.Length > 4 && INTERVAL == "INTERVAL" ? int.Parse(INTERVALCOUNT) : 1;
int position = ruleArray.Length > 4 && INTERVAL == "INTERVAL" ? 6 : BYMONTHDAYPOSITION;
if (BYMONTHDAY == "BYMONTHDAY")
int monthDate = int.Parse(BYMONTHDAYCOUNT);
int currDate = int.Parse(startDate.Day.ToString());
var temp = new DateTime(addDate.Year, addDate.Month, monthDate);
addDate = monthDate < currDate ? temp.AddMonths(1) : temp;
if (recCount == 0 && UNTIL == null)
for (int i = 0; i < recCount; i++)
addDate = GetByMonthDayDateCollection(addDate, RecDateCollection, monthDate, MyMonthGap);
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
addDate = GetByMonthDayDateCollection(addDate, RecDateCollection, monthDate, MyMonthGap);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
if (recCount == 0 && UNTIL == null)
for (int i = 0; i < recCount; i++)
if (addDate.Day == startDate.Day)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
addDate = new DateTime(addDate.Year, addDate.Month, DateTime.DaysInMonth(addDate.Year, addDate.Month));
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
if (addDate.Day == startDate.Day)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
addDate = new DateTime(addDate.Year, addDate.Month, DateTime.DaysInMonth(addDate.Year, addDate.Month));
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
else if (BYDAY == "BYDAY")
if (recCount == 0 && UNTIL == null)
while (RecDateCollection.Count < recCount)
var weekCount = MondaysInMonth(addDate);
var monthStart = new DateTime(addDate.Year, addDate.Month, 1);
DateTime weekStartDate = monthStart.AddDays(-(int)(monthStart.DayOfWeek));
var monthStartWeekday = (int)(monthStart.DayOfWeek);
int nthweekDay = GetWeekDay(BYDAYVALUE) - 1;
int.TryParse(BYSETPOSCOUNT, out setPosCount);
if (monthStartWeekday <= nthweekDay)
bySetPos = weekCount + setPosCount;
bySetPos = weekCount + setPosCount;
addDate = weekStartDate.AddDays((nthWeek) * 7);
addDate = addDate.AddDays(nthweekDay);
if (addDate.CompareTo(startDate.Date) < 0)
addDate = addDate.AddMonths(1);
if (weekCount == 6 && addDate.Day == 23)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
else if (weekCount == 6 && addDate.Day == 24)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
if (addDate.AddDays(7).Day != days)
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
else if (!(addDate.Day <= 23 && int.Parse(BYSETPOSCOUNT) == -1))
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
var weekCount = MondaysInMonth(addDate);
var monthStart = new DateTime(addDate.Year, addDate.Month, 1);
DateTime weekStartDate = monthStart.AddDays(-(int)(monthStart.DayOfWeek));
var monthStartWeekday = (int)(monthStart.DayOfWeek);
int nthweekDay = GetWeekDay(BYDAYVALUE) - 1;
int.TryParse(BYSETPOSCOUNT, out setPosCount);
if (monthStartWeekday <= nthweekDay)
bySetPos = weekCount + setPosCount;
bySetPos = weekCount + setPosCount;
addDate = weekStartDate.AddDays((nthWeek) * 7);
addDate = addDate.AddDays(nthweekDay);
if (addDate.CompareTo(startDate.Date) < 0)
addDate = addDate.AddMonths(1);
if (weekCount == 6 && addDate.Day == 23)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
else if (weekCount == 6 && addDate.Day == 24)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
if (addDate.AddDays(7).Day != days)
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
else if (!(addDate.Day <= 23 && int.Parse(BYSETPOSCOUNT) == -1))
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
else if (YEARLY == "YEARLY")
int YyYearGap = ruleArray.Length > 4 && INTERVAL == "INTERVAL" ? int.Parse(INTERVALCOUNT) : 1;
int position = ruleArray.Length > 4 && INTERVAL == "INTERVAL" ? 6 : BYMONTHDAYPOSITION;
if (BYMONTHDAY == "BYMONTHDAY")
int monthIndex = int.Parse(BYMONTHCOUNT);
int dayIndex = int.Parse(BYMONTHDAYCOUNT);
if (monthIndex > 0 && monthIndex <= 12)
int bound = DateTime.DaysInMonth(addDate.Year, monthIndex);
var specificDate = new DateTime(addDate.Year, monthIndex, dayIndex);
if (specificDate.Date < addDate.Date)
addDate = addDate.AddYears(1);
if (recCount == 0 && UNTIL == null)
for (int i = 0; i < recCount; i++)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
else if (BYDAY == "BYDAY")
int monthIndex = int.Parse(BYMONTHCOUNT);
if (recCount == 0 && UNTIL == null)
while (RecDateCollection.Count < recCount)
var weekCount = MondaysInMonth(addDate);
var monthStart = new DateTime(addDate.Year, monthIndex, 1);
DateTime weekStartDate = monthStart.AddDays(-(int)(monthStart.DayOfWeek));
var monthStartWeekday = (int)(monthStart.DayOfWeek);
int nthweekDay = GetWeekDay(BYDAYVALUE) - 1;
int.TryParse(BYSETPOSCOUNT, out setPosCount);
if (monthStartWeekday <= nthweekDay)
bySetPos = weekCount + setPosCount;
bySetPos = weekCount + setPosCount;
addDate = weekStartDate.AddDays((nthWeek) * 7);
addDate = addDate.AddDays(nthweekDay);
if (addDate.CompareTo(startDate.Date) < 0)
addDate = addDate.AddYears(1);
if (weekCount == 6 && addDate.Day == 23)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
else if (weekCount == 6 && addDate.Day == 24)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
if (addDate.AddDays(7).Day != days)
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
else if (!(addDate.Day <= 23 && BYSETPOSCOUNT != "" && int.Parse(BYSETPOSCOUNT) == -1))
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
bool IsUntilDateReached = false;
while (!IsUntilDateReached)
var weekCount = MondaysInMonth(addDate);
var monthStart = new DateTime(addDate.Year, monthIndex, 1);
DateTime weekStartDate = monthStart.AddDays(-(int)(monthStart.DayOfWeek));
var monthStartWeekday = (int)(monthStart.DayOfWeek);
int nthweekDay = GetWeekDay(BYDAYVALUE) - 1;
int.TryParse(BYSETPOSCOUNT, out setPosCount);
if (monthStartWeekday <= nthweekDay)
bySetPos = weekCount + setPosCount;
bySetPos = weekCount + setPosCount;
addDate = weekStartDate.AddDays((nthWeek) * 7);
addDate = addDate.AddDays(nthweekDay);
if (addDate.CompareTo(startDate.Date) < 0)
addDate = addDate.AddYears(1);
if (weekCount == 6 && addDate.Day == 23)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
else if (weekCount == 6 && addDate.Day == 24)
int days = DateTime.DaysInMonth(addDate.Year, addDate.Month);
if (addDate.AddDays(7).Day != days)
addDate = addDate.AddDays(7);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
else if (!(addDate.Day <= 23 && int.Parse(BYSETPOSCOUNT) == -1))
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddYears(YyYearGap);
int statusValue = DateTime.Compare(addDate.Date, Convert.ToDateTime(UNTIL));
IsUntilDateReached = true;
var filteredDates = RecDateCollection.Except(exDateList).ToList();
public static int MondaysInMonth(DateTime thisMonth)
DateTime today = thisMonth;
int daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);
DateTime firstOfMonth = new DateTime(today.Year, today.Month, 1);
int firstDayOfMonth = (int)firstOfMonth.DayOfWeek;
int weeksInMonth = (int)Math.Ceiling((firstDayOfMonth + daysInMonth) / 7.0);
private static void GetWeeklyDateCollection(DateTime addDate, string[] weeklyRule, List<DateTime> RecDateCollection)
switch (addDate.DayOfWeek)
if (weeklyRule[WEEKLYBYDAYPOS].Contains("SU"))
RecDateCollection.Add(addDate.Date);
if (weeklyRule[WEEKLYBYDAYPOS].Contains("MO"))
RecDateCollection.Add(addDate.Date);
if (weeklyRule[WEEKLYBYDAYPOS].Contains("TU"))
RecDateCollection.Add(addDate.Date);
case DayOfWeek.Wednesday:
if (weeklyRule[WEEKLYBYDAYPOS].Contains("WE"))
RecDateCollection.Add(addDate.Date);
if (weeklyRule[WEEKLYBYDAYPOS].Contains("TH"))
RecDateCollection.Add(addDate.Date);
if (weeklyRule[WEEKLYBYDAYPOS].Contains("FR"))
RecDateCollection.Add(addDate.Date);
if (weeklyRule[WEEKLYBYDAYPOS].Contains("SA"))
RecDateCollection.Add(addDate.Date);
private static DateTime GetByMonthDayDateCollection(DateTime addDate, List<DateTime> RecDateCollection, int monthDate, int MyMonthGap)
if (addDate.Month == 2 && monthDate > 28)
addDate = new DateTime(addDate.Year, addDate.Month, DateTime.DaysInMonth(addDate.Year, 2));
addDate = addDate.AddMonths(MyMonthGap);
addDate = new DateTime(addDate.Year, addDate.Month, monthDate);
RecDateCollection.Add(addDate.Date);
addDate = addDate.AddMonths(MyMonthGap);
private static DateTime GetByDayDateValue(DateTime addDate, DateTime monthStart)
DateTime weekStartDate = monthStart.AddDays(-(int)(monthStart.DayOfWeek));
var monthStartWeekday = (int)(monthStart.DayOfWeek);
int nthweekDay = GetWeekDay(BYDAYVALUE) - 1;
if (monthStartWeekday <= nthweekDay)
nthWeek = int.Parse(BYSETPOSCOUNT) - 1;
nthWeek = int.Parse(BYSETPOSCOUNT);
addDate = weekStartDate.AddDays((nthWeek) * 7);
addDate = addDate.AddDays(nthweekDay);
private static void FindExdateList(string ruleException)
exDateList = new List<DateTime>();
var exDates = ruleException.Split(',');
for (int i = 0; i < exDates.Length; i++)
StringBuilder sb = new StringBuilder(exDates[i]);
sb.Insert(4, '-'); sb.Insert(7, '-'); sb.Insert(13, ':'); sb.Insert(16, ':');
DateTimeOffset value = DateTimeOffset.ParseExact(sb.ToString(), "yyyy-MM-dd'T'HH:mm:ss'Z'",
CultureInfo.InvariantCulture);
exDateList.Add(value.DateTime.Date);
private static int GetWeekDay(string weekDay)
private static void FindWeeklyRule(string[] weeklyRule)
for (int i = 0; i < weeklyRule.Length; i++)
if (weeklyRule[i].Contains("BYDAY"))
WEEKLYBYDAY = weeklyRule[i];
private static void FindKeyIndex(string[] ruleArray, DateTime startDate)
for (int i = 0; i < ruleArray.Length; i++)
if (ruleArray[i].Contains("COUNT"))
RECCOUNT = ruleArray[i + 1];
if (ruleArray[i].Contains("UNTIL"))
StringBuilder sb = new StringBuilder(ruleArray[i + 1]);
sb.Insert(4, '-'); sb.Insert(7, '-'); sb.Insert(13, ':'); sb.Insert(16, ':');
DateTimeOffset value = DateTimeOffset.ParseExact(sb.ToString(), "yyyy-MM-dd'T'HH:mm:ss'Z'",
CultureInfo.InvariantCulture);
UNTIL = value.DateTime.Date;
if (ruleArray[i].Contains("DAILY"))
if (ruleArray[i].Contains("WEEKLY"))
if (ruleArray[i].Contains("INTERVAL"))
INTERVALCOUNT = ruleArray[i + 1];
if (ruleArray[i].Contains("MONTHLY"))
if (ruleArray[i].Contains("YEARLY"))
if (ruleArray[i].Contains("BYSETPOS"))
var weekCount = MondaysInMonth(startDate);
BYSETPOSCOUNT = ruleArray[i + 1];
if (ruleArray[i].Contains("BYDAY"))
BYDAYVALUE = ruleArray[i + 1];
if (ruleArray[i].Contains("BYMONTHDAY"))
BYMONTHDAY = ruleArray[i];
BYMONTHDAYCOUNT = ruleArray[i + 1];
if (ruleArray[i].Contains("BYMONTH"))
BYMONTHCOUNT = ruleArray[i + 1];