All posts in Schedule

It’s been a while since I have had anything to say and that’s mostly because of how busy I’ve been recently. In that time though, I have posted a number of my frameworks on NuGet located here. And to complement those frameworks, I have started to write the SandCastle documentation so that users can understand how my methods work. So, with all that in mind, I now have plently of material to blog about.

Today, we are going to talk briefly about scheduling. Or, more importantly, how we can write code that will provide a set of dates to complement a variety of date ranges or number of desired occurrences within a given time frame. To best understand this we should look at pulling a set of dates by days, weeks, months, and years. So, you will see a lot of similar patterns.

Before I get into it, let me talk about the difference between evaluating dates By Schedule vs By Occurrence.

 
By Schedule is concerned with: a start date, and an end date. This is because we are looking for the number of occurrences that happen between 2 static dates. Ex. Run this script every Tuesday until 2/20/2020.

By Occurrence is a little different. Instead it cares about start date, number of occurrences, and a maximum number of years to allow as an upper range. This is because here, we are looking for the dates that result from a specified number of occurrences. Ex. run this script up to 60 times within the next 5 years.

 
Assessing Dates By Days

To schedule something in terms of days, the most important variable to consider is the number of days between each instance. Essentially, we just need to enumerate through the dates by the number of days until we hit the end date or the number of occurrences depending if we query by schedule or by occurrence.

The source code would look something like this:
 


/// <summary>
/// Gets a list of valid dates related to days within a scheduled range.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="endDate">The end date.</param>
/// <param name="numberOfDays">The number of days to evaluate.</param>
/// <returns></returns>
public static DateTime[] GetValidDaysBySchedule(
    DateTime startDate, DateTime endDate, int numberOfDays)
{
	// List to return
	var list = new List<DateTime>();

	// Set first date to evaluate to the start date
	var currentDate = startDate;

	// Must have a valid start and end date, and the end date must be later in time than the 
	// start date.
	if (startDate == default(DateTime) || endDate == default(DateTime) ||
		!(endDate >= startDate)) return list.ToArray();

	// Process
	// 1) Do not exceed the end date, and
	while (endDate.Subtract(currentDate).TotalDays >= 0)
	{
		// Add date
		list.Add(currentDate);

		// Get next date
		currentDate = currentDate.AddDays(numberOfDays);
	}
	return list.ToArray();
}

/// <summary>
/// Gets a list of valid dates related to days within a number of occurrences.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="numberOfDays">The number of days.</param>
/// <param name="numberOfOccurrences">The number of occurrences. The default is 1.</param>
/// <param name="maximumYearsAllowed">The maximum years allowed. The default is 10.</param>
/// <returns></returns>
public static DateTime[] GetValidDaysByOccurrence(
    DateTime startDate, int numberOfDays, int numberOfOccurrences = 1, int maximumYearsAllowed = 1)
{
	// List to return
	var list = new List<DateTime>();

	// Set first date to evaluate to the start date
	var currentDate = startDate;

	// Must have a valid start and end date, and the occurrence count must not be exceeded.
	if (startDate == default(DateTime) || list.Count >= numberOfOccurrences)
		return list.ToArray();

	// Process
	// 1) Do not exceed occurrence count, and 
	// 2) do not exceed the maximum allowed years in a date range.
	var maxDate = startDate.AddYears(maximumYearsAllowed);
	while (list.Count < numberOfOccurrences && maxDate >= currentDate)
	{
		// Add date
		list.Add(currentDate);

		// Get next date
		currentDate = currentDate.AddDays(numberOfDays);
	}
	return list.ToArray();
}

 

An example of how to use this in a console application:


// Main
static void Main(string[] args)
{
	var startDate = new DateTime(2018, 2, 17);
	var endDate = startDate.AddMonths(4);

	// Occurs every 10 days up to the end date
	Console.WriteLine("By date range:");
	var dates = ScheduleHelper.GetValidDaysBySchedule(startDate, endDate, 10);
	foreach (var date in dates)
	{
		Console.WriteLine($"{date:MM/dd/yyyy, dddd}");
	}

	// Spacer
	Console.WriteLine("");

	// Occurs every 10 days, up to 10 times, not to exceed 1 year
	Console.WriteLine("By # of occurrences:");
	var dates2 = ScheduleHelper.GetValidDaysByOccurrence(startDate, 10, 10, 1);
	foreach (var date in dates2)
	{
		Console.WriteLine($"{date:MM/dd/yyyy, dddd}");
	}

	// Hold
	Console.Read();
}

/* Result:
 *
 * By date range:
 * 02/17/2018, Saturday
 * 02/27/2018, Tuesday
 * 03/09/2018, Friday
 * 03/19/2018, Monday
 * 03/29/2018, Thursday
 * 04/08/2018, Sunday
 * 04/18/2018, Wednesday
 * 04/28/2018, Saturday
 * 05/08/2018, Tuesday
 * 05/18/2018, Friday
 * 05/28/2018, Monday
 * 06/07/2018, Thursday
 * 06/17/2018, Sunday
 * 
 * By # of occurrences:
 * 02/17/2018, Saturday
 * 02/27/2018, Tuesday
 * 03/09/2018, Friday
 * 03/19/2018, Monday
 * 03/29/2018, Thursday
 * 04/08/2018, Sunday
 * 04/18/2018, Wednesday
 * 04/28/2018, Saturday
 * 05/08/2018, Tuesday
 * 05/18/2018, Friday
 */

 
Assessing Dates By Weeks

To schedule something in terms of weeks, we not only need to look at the number of weeks between each occurrence, we also need to specify which days of the week are relevant. Performing evaluations of weeks are in my opinion the most complex of the 4 types.

The source code would look something like this:
 


/// <summary>
/// Days of the week
/// </summary>
public enum DaysOfTheWeek
{
	/// <summary>
	/// Sunday
	/// </summary>
	Sunday = 0,

	/// <summary>
	/// Monday
	/// </summary>
	Monday = 1,

	/// <summary>
	/// Tuesday
	/// </summary>
	Tuesday = 2,

	/// <summary>
	/// Wednesday
	/// </summary>
	Wednesday = 3,

	/// <summary>
	/// Thursday
	/// </summary>
	Thursday = 4,

	/// <summary>
	/// Friday
	/// </summary>
	Friday = 5,

	/// <summary>
	/// Saturday
	/// </summary>
	Saturday = 6
}

/// <summary>
/// Gets a list of valid dates related to weeks within a scheduled range.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="endDate">The end date.</param>
/// <param name="numberOfWeeks">The number of weeks to skip per block of selected days.</param>
/// <param name="selectedDays">The selected days of the week the event occurs.</param>
/// <returns></returns>
public static DateTime[] GetValidWeeksBySchedule(
	DateTime startDate, DateTime endDate, int numberOfWeeks, DaysOfTheWeek[] selectedDays)
{
	// List to return
	var list = new List<DateTime>();

	// Get the start of the week
	var dayOfWeek = (int)startDate.DayOfWeek;

	// Set first date to evaluate to the start date
	var currentDate = startDate;

	// Get selected days and convert to their integer values
	// If no days were specified, then exit.
	var validDays = selectedDays.Select(x => (int)x).ToArray();
	if (!validDays.Any()) return list.ToArray();

	// Must have a valid start and end date, and
	// the end date must be later in time than the start date.
	if (startDate == default(DateTime) || endDate == default(DateTime) ||
		!(endDate >= startDate))
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed the end date
	while (endDate.Subtract(currentDate).TotalDays >= 0)
	{
		// Get the day of the week (value)
		var currentDayOfWeek = (int)currentDate.DayOfWeek;

		// Evaluate against selected says of the week
		if (validDays.Contains(currentDayOfWeek)) list.Add(currentDate);

		// Evaluate the next day
		var nextDay = currentDate.AddDays(1);

		// If the day of the week is not the original, and number of weeks is no greater than 1
		// Set the date as the next day. Otherwise, jump by the number of weeks specified.
		if ((int)nextDay.DayOfWeek != dayOfWeek || numberOfWeeks <= 1)
		{
			currentDate = nextDay;
		}
		else
		{
			var interval = 7 * (numberOfWeeks - 1);
			currentDate = nextDay.AddDays(interval);
		}
	}

	// Return
	return list.ToArray();
}

/// <summary>
/// Gets a list of valid dates related to weeks within a number of occurrences.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="numberOfWeeks">The number of weeks to skip per block of selected days.</param>
/// <param name="selectedDays">The selected days of the week the event occurs.</param>
/// <param name="numberOfOccurrences">The number of occurrences. The default is 1.</param>
/// <param name="maximumYearsAllowed">The maximum years allowed. The default is 10.</param>
/// <returns></returns>
public static DateTime[] GetValidWeeksByOccurrence(
	DateTime startDate, int numberOfWeeks,
	DaysOfTheWeek[] selectedDays, int numberOfOccurrences = 1, int maximumYearsAllowed = 10)
{
	// List to return
	var list = new List<DateTime>();

	// Get the start of the week
	var dayOfWeek = (int)startDate.DayOfWeek;

	// Set first date to evaluate to the start date
	var currentDate = startDate;

	// Get selected days and convert to their integer values
	// If no days were specified, then exit.
	var validDays = selectedDays.Select(x => (int)x).ToArray();
	if (!validDays.Any()) return list.ToArray();

	// Must have a valid start and end date, and
	// the occurrence count must not be exceeded.
	if (startDate == default(DateTime) || list.Count >= numberOfOccurrences)
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed occurrence, and 
	// 2) do not exceed the maximum allowed years in a date 
	// range.
	var maxDate = startDate.AddYears(maximumYearsAllowed);
	while (list.Count < numberOfOccurrences && maxDate >= currentDate)
	{
		// Get the day of the week (value)
		var currentDayOfWeek = (int)currentDate.DayOfWeek;

		// Evaluate against selected says of the week
		if (validDays.Contains(currentDayOfWeek)) list.Add(currentDate);

		// Evaluate the next day
		var nextDay = currentDate.AddDays(1);

		// If the day of the week is not the original, and number of weeks is no greater than 1
		// Set the date as the next day. Otherwise, jump by the number of weeks specified.
		if ((int)nextDay.DayOfWeek != dayOfWeek || numberOfWeeks <= 1)
		{
			currentDate = nextDay;
		}
		else
		{
			var interval = 7 * (numberOfWeeks - 1);
			currentDate = nextDay.AddDays(interval);
		}
	}

	// Return
	return list.ToArray();
}

 

An example of how to use this in a console application:


// Main
static void Main(string[] args)
{
	var startDate = new DateTime(2018, 2, 17);
	var endDate = startDate.AddYears(1);

	// Occurs every 2 weeks on Sunday, Monday, and Thursday not to exceed the end date.
	var dates = ScheduleHelper.GetValidWeeksBySchedule(startDate, endDate, 2,
		new[] { DaysOfTheWeek.Sunday, DaysOfTheWeek.Monday, DaysOfTheWeek.Thursday });
	Console.WriteLine($"By date range ({dates.Length}):");
	foreach (var date in dates)
	{
		Console.WriteLine($"{date:MM/dd/yyy, dddd}");
	}

	// Spacer
	Console.WriteLine("");

	// Occurs up to 30 times on Sunday, Monday, and Thursday no longer than 1 year.
	var dates2 = ScheduleHelper.GetValidWeeksByOccurrence(startDate, 1,
		new[] { Enums.DaysOfTheWeek.Sunday, Enums.DaysOfTheWeek.Monday, Enums.DaysOfTheWeek.Thursday },
		30, 1);
	Console.WriteLine($"By # of occurrences ({dates2.Length}):");
	foreach (var date in dates2)
	{
		Console.WriteLine($"{date:MM/dd/yyyy, dddd}");
	}

	// Hold
	Console.Read();
}

/* Result:
 *
 * By date range (79):
 * 02/18/2018, Sunday
 * 02/19/2018, Monday
 * 02/22/2018, Thursday
 * 03/04/2018, Sunday
 * 03/05/2018, Monday
 * 03/08/2018, Thursday
 * 03/18/2018, Sunday
 * 03/19/2018, Monday
 * 03/22/2018, Thursday
 * 04/01/2018, Sunday
 * 04/02/2018, Monday
 * 04/05/2018, Thursday
 * 04/15/2018, Sunday
 * 04/16/2018, Monday
 * 04/19/2018, Thursday
 * 04/29/2018, Sunday
 * 04/30/2018, Monday
 * 05/03/2018, Thursday
 * 05/13/2018, Sunday
 * 05/14/2018, Monday
 * 05/17/2018, Thursday
 * 05/27/2018, Sunday
 * 05/28/2018, Monday
 * 05/31/2018, Thursday
 * 06/10/2018, Sunday
 * 06/11/2018, Monday
 * 06/14/2018, Thursday
 * 06/24/2018, Sunday
 * 06/25/2018, Monday
 * 06/28/2018, Thursday
 * 07/08/2018, Sunday
 * 07/09/2018, Monday
 * 07/12/2018, Thursday
 * 07/22/2018, Sunday
 * 07/23/2018, Monday
 * 07/26/2018, Thursday
 * 08/05/2018, Sunday
 * 08/06/2018, Monday
 * 08/09/2018, Thursday
 * 08/19/2018, Sunday
 * 08/20/2018, Monday
 * 08/23/2018, Thursday
 * 09/02/2018, Sunday
 * 09/03/2018, Monday
 * 09/06/2018, Thursday
 * 09/16/2018, Sunday
 * 09/17/2018, Monday
 * 09/20/2018, Thursday
 * 09/30/2018, Sunday
 * 10/01/2018, Monday
 * 10/04/2018, Thursday
 * 10/14/2018, Sunday
 * 10/15/2018, Monday
 * 10/18/2018, Thursday
 * 10/28/2018, Sunday
 * 10/29/2018, Monday
 * 11/01/2018, Thursday
 * 11/11/2018, Sunday
 * 11/12/2018, Monday
 * 11/15/2018, Thursday
 * 11/25/2018, Sunday
 * 11/26/2018, Monday
 * 11/29/2018, Thursday
 * 12/09/2018, Sunday
 * 12/10/2018, Monday
 * 12/13/2018, Thursday
 * 12/23/2018, Sunday
 * 12/24/2018, Monday
 * 12/27/2018, Thursday
 * 01/06/2019, Sunday
 * 01/07/2019, Monday
 * 01/10/2019, Thursday
 * 01/20/2019, Sunday
 * 01/21/2019, Monday
 * 01/24/2019, Thursday
 * 02/03/2019, Sunday
 * 02/04/2019, Monday
 * 02/07/2019, Thursday
 * 02/17/2019, Sunday
 * 
 * By # of occurrences (30):
 * 02/18/2018, Sunday
 * 02/19/2018, Monday
 * 02/22/2018, Thursday
 * 02/25/2018, Sunday
 * 02/26/2018, Monday
 * 03/01/2018, Thursday
 * 03/04/2018, Sunday
 * 03/05/2018, Monday
 * 03/08/2018, Thursday
 * 03/11/2018, Sunday
 * 03/12/2018, Monday
 * 03/15/2018, Thursday
 * 03/18/2018, Sunday
 * 03/19/2018, Monday
 * 03/22/2018, Thursday
 * 03/25/2018, Sunday
 * 03/26/2018, Monday
 * 03/29/2018, Thursday
 * 04/01/2018, Sunday
 * 04/02/2018, Monday
 * 04/05/2018, Thursday
 * 04/08/2018, Sunday
 * 04/09/2018, Monday
 * 04/12/2018, Thursday
 * 04/15/2018, Sunday
 * 04/16/2018, Monday
 * 04/19/2018, Thursday
 * 04/22/2018, Sunday
 * 04/23/2018, Monday
 * 04/26/2018, Thursday
 */

 
Assessing Dates By Months

To schedule something in terms of months, we need to assess the number of months between each occurrence, and the day of the month it will occur on.

The source code would look like this:
 


/// <summary>
/// Gets a list of valid dates related to months within a scheduled range.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="endDate">The end date.</param>
/// <param name="numberOfMonths">The number of months to skip per date.</param>
/// <param name="dayOfMonth">The day of the month the event occurs.</param>
/// <returns></returns>
public static DateTime[] GetValidMonthsBySchedule(
	DateTime startDate, DateTime endDate, int numberOfMonths,
	int dayOfMonth)
{
	// List to return
	var list = new List<DateTime>();

	// Set current day as the start date with the time stripped off
	var currentDate = new DateTime(startDate.Year, startDate.Month, dayOfMonth);

	// Must have a valid start and end date, and
	// the end date must be later in time than the start date.
	if (startDate == default(DateTime) || endDate == default(DateTime) ||
		!(endDate >= startDate))
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed the end date
	while (endDate.Subtract(currentDate).TotalDays >= 0)
	{
		// Add to list
		list.Add(currentDate);

		// Get new date
		currentDate = currentDate.AddMonths(numberOfMonths);
	}

	// Return
	return list.ToArray();
}

/// <summary>
/// Gets a list of valid dates related to months within a number of occurrences.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="numberOfMonths">The number of months to skip per date.</param>
/// <param name="dayOfMonth">The day of the month the event occurs.</param>
/// <param name="numberOfOccurrences">The number of occurrences. The default is 1.</param>
/// <param name="maximumYearsAllowed">The maximum years allowed. The default is 10.</param>
/// <returns></returns>
public static DateTime[] GetValidMonthsByOccurrence(
	DateTime startDate, int numberOfMonths,
	int dayOfMonth, int numberOfOccurrences = 1, int maximumYearsAllowed = 10)
{
	// List to return
	var list = new List<DateTime>();

	// Set current day as the start date with the time stripped off
	var currentDate = new DateTime(startDate.Year, startDate.Month, dayOfMonth);

	// Must have a valid start and end date, and the occurrence count must not be exceeded.
	if (startDate == default(DateTime) || list.Count >= numberOfOccurrences)
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed occurrence, and 
	// 2) do not exceed the maximum allowed years in a date range.
	var maxDate = startDate.AddYears(maximumYearsAllowed);
	while (list.Count < numberOfOccurrences && maxDate >= currentDate)
	{
		// Add to list
		list.Add(currentDate);

		// Get new date
		currentDate = currentDate.AddMonths(numberOfMonths);
	}

	// Return
	return list.ToArray();
}

 

An example of how to use this in a console application:


// Main
static void Main(string[] args)
{
	var startDate = new DateTime(2018, 2, 17);
	var endDate = startDate.AddYears(2);

	// Occurs on the 5th day of every month until the end date
	var dates = ScheduleHelper.GetValidMonthsBySchedule(startDate, endDate, 1, 5);
	Console.WriteLine($"By date range ({dates.Length}):");
	foreach (var date in dates)
	{
		Console.WriteLine($"{date:MM/dd/yyy, dddd}");
	}

	// Spacer
	Console.WriteLine("");

	// Occurs on the 5th day of every month until 20 occurrences have been reached.
	var dates2 = ScheduleHelper.GetValidMonthsByOccurrence(startDate, 1, 5, 20, 2);
	Console.WriteLine($"By # of occurrences ({dates2.Length}):");
	foreach (var date in dates2)
	{
		Console.WriteLine($"{date:MM/dd/yyyy, dddd}");
	}

	// Hold
	Console.Read();
}

/* Result:
 *
 * By date range (25):
 * 02/05/2018, Monday
 * 03/05/2018, Monday
 * 04/05/2018, Thursday
 * 05/05/2018, Saturday
 * 06/05/2018, Tuesday
 * 07/05/2018, Thursday
 * 08/05/2018, Sunday
 * 09/05/2018, Wednesday
 * 10/05/2018, Friday
 * 11/05/2018, Monday
 * 12/05/2018, Wednesday
 * 01/05/2019, Saturday
 * 02/05/2019, Tuesday
 * 03/05/2019, Tuesday
 * 04/05/2019, Friday
 * 05/05/2019, Sunday
 * 06/05/2019, Wednesday
 * 07/05/2019, Friday
 * 08/05/2019, Monday
 * 09/05/2019, Thursday
 * 10/05/2019, Saturday
 * 11/05/2019, Tuesday
 * 12/05/2019, Thursday
 * 01/05/2020, Sunday
 * 02/05/2020, Wednesday
 * 
 * By # of occurrences (20):
 * 02/05/2018, Monday
 * 03/05/2018, Monday
 * 04/05/2018, Thursday
 * 05/05/2018, Saturday
 * 06/05/2018, Tuesday
 * 07/05/2018, Thursday
 * 08/05/2018, Sunday
 * 09/05/2018, Wednesday
 * 10/05/2018, Friday
 * 11/05/2018, Monday
 * 12/05/2018, Wednesday
 * 01/05/2019, Saturday
 * 02/05/2019, Tuesday
 * 03/05/2019, Tuesday
 * 04/05/2019, Friday
 * 05/05/2019, Sunday
 * 06/05/2019, Wednesday
 * 07/05/2019, Friday
 * 08/05/2019, Monday
 * 09/05/2019, Thursday
 */

 
Assessing Dates By Years

Finally, to schedule something in terms of years, we need to assess the number of years between each occurrence, the specific month in that year, and the specific day in that month.

The source code would look like this:
 


/// <summary>
/// Gets a list of valid dates related to years within a scheduled range.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="endDate">The end date.</param>
/// <param name="numberOfYears">The number of years to skip per date.</param>
/// <param name="month">The month the event occurs.</param>
/// <param name="day">The day of the month the event occurs.</param>
/// <returns></returns>
public static DateTime[] GetValidYearsBySchedule(
	DateTime startDate, DateTime endDate, int numberOfYears, int month, int day)
{
	// List to return
	var list = new List<DateTime>();

	// Set current day as the start date with the time stripped off
	var currentDate = new DateTime(startDate.Year, month, day);

	// Must have a valid start and end date, and
	// the end date must be later in time than the start date.
	if (startDate == default(DateTime) || endDate == default(DateTime) ||
		!(endDate >= startDate))
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed the end date, and
	while (endDate.Subtract(currentDate).TotalDays >= 0)
	{
		// Add to list
		list.Add(currentDate);

		// Get new date
		currentDate = currentDate.AddYears(numberOfYears);
	}

	// Return
	return list.ToArray();
}

/// <summary>
/// Gets a list of valid dates related to years within a scheduled range.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="numberOfYears">The number of years to skip per date.</param>
/// <param name="month">The month the event occurs.</param>
/// <param name="day">The day of the month the event occurs.</param>
/// <param name="numberOfOccurrences">The number of occurrences. The default is 1.</param>
/// <param name="maximumYearsAllowed">The maximum years allowed. The default is 10.</param>
/// <returns></returns>
public static DateTime[] GetValidYearsByOccurrence(
	DateTime startDate, int numberOfYears,
	int month, int day, int numberOfOccurrences = 1, int maximumYearsAllowed = 10)
{
	// List to return
	var list = new List<DateTime>();

	// Set current day as the start date with the time stripped off
	var currentDate = new DateTime(startDate.Year, month, day);

	// Must have a valid start and end date, and
	// the occurrence count must not be exceeded.
	if ((startDate == default(DateTime)) || list.Count >= numberOfOccurrences)
	{
		return list.ToArray();
	}

	// Process
	// 1) Do not exceed occurrence, and 
	// 2) do not exceed the maximum allowed years in a date range.
	var maxDate = startDate.AddYears(maximumYearsAllowed);
	while (list.Count < numberOfOccurrences && maxDate >= currentDate)
	{
		// Add to list
		list.Add(currentDate);

		// Get new date
		currentDate = currentDate.AddYears(numberOfYears);
	}

	// Return
	return list.ToArray();
}

 

An example of how to use this in a console application:


// Main
static void Main(string[] args)
{
	var startDate = new DateTime(2018, 2, 17);
	var endDate = startDate.AddYears(5);

	// Occurs on the 5th day of February of every year until the end date
	var dates = ScheduleHelper.GetValidYearsBySchedule(startDate, endDate, 1, 2, 5);
	Console.WriteLine($"By date range ({dates.Length}):");
	foreach (var date in dates)
	{
		Console.WriteLine($"{date:MM/dd/yyy, dddd}");
	}

	// Spacer
	Console.WriteLine("");

	// Occurs on the 5th day of February of every year until 50 occurrences have been reached.
	var dates2 = ScheduleHelper.GetValidYearsByOccurrence(startDate, 1, 2, 5, 50, 5);
	Console.WriteLine($"By # of occurrences ({dates2.Length}):");
	foreach (var date in dates2)
	{
		Console.WriteLine($"{date:MM/dd/yyyy, dddd}");
	}

	// Hold
	Console.Read();
}

/* Result:
 *
 * By date range (6):
 * 02/05/2018, Monday
 * 02/05/2019, Tuesday
 * 02/05/2020, Wednesday
 * 02/05/2021, Friday
 * 02/05/2022, Saturday
 * 02/05/2023, Sunday
 * 
 * By # of occurrences (6):
 * 02/05/2018, Monday
 * 02/05/2019, Tuesday
 * 02/05/2020, Wednesday
 * 02/05/2021, Friday
 * 02/05/2022, Saturday
 * 02/05/2023, Sunday
 */

 
And that’s all there really is to it. Once you see the code for yourself you can understand that it’s not nearly as complex as you might have originally thought.

I hope that helped. So, until next time – Happy Coding!