Click here to Skip to main content
15,894,539 members
Articles / Programming Languages / C#

Recurring Date Generator with Pattern Coding

Rate me:
Please Sign up or sign in to vote.
4.95/5 (51 votes)
4 Sep 2007CPOL4 min read 147K   6.9K   98  
Create recurring dates using a user-defined pattern. Create recurring dates from a coded value that defines what the pattern should be.
using System;

namespace RecurrenceGenerator
{
    #region Class-specific Enums
    /// <summary>
    /// The Regeneration type. Is this on a specific day of the month, a custom date, or after the occurrence is completed.
    /// </summary>
    public enum MonthlyRegenType { NotSet = -1, OnSpecificDayOfMonth, OnCustomDateFormat, AfterOccurrenceCompleted };
    /// <summary>
    /// First part of a custom date. This would be First, Second, etc. item of the month.
    /// </summary>
    public enum MonthlySpecificDatePartOne { NotSet = -1, First, Second, Third, Fourth, Last };
    /// <summary>
    /// Second part of a custom date. This is day of week, weekend day, etc.
    /// </summary>
    public enum MonthlySpecificDatePartTwo { NotSet = -1, Day, Weekday, WeekendDay, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

#endregion //Class-specific Enums

    public class MonthlyRecurrenceSettings : RecurrenceSettings
    {
        #region Constructors
        /// <summary>
        /// Get dates by Start date only. This is for no ending date values.
        /// </summary>
        /// <param name="startDate"></param>
        public MonthlyRecurrenceSettings(DateTime startDate) : base(startDate) { }
        /// <summary>
        /// Get dates by Start and End date boundries.
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        public MonthlyRecurrenceSettings(DateTime startDate, DateTime endDate): base(startDate, endDate){}
        /// <summary>
        /// Get dates by Start date and number of occurrences.
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="numberOfOccurrences"></param>
        public MonthlyRecurrenceSettings(DateTime startDate, int numberOfOccurrences): base(startDate, numberOfOccurrences){ }
        #endregion

        #region Private Fields
        int regenerateOnSpecificDateDayValue;
        int regenEveryXMonths = 1;
        int adjustmentValue;
        bool getNextDateValue;
        DateTime nextDateValue;
        MonthlyRegenType regenType = MonthlyRegenType.NotSet;
        MonthlySpecificDatePartOne specificDatePartOne = MonthlySpecificDatePartOne.NotSet;
        MonthlySpecificDatePartTwo specificDatePartTwo = MonthlySpecificDatePartTwo.NotSet;
        #endregion

        #region Private Procedures
        /// <summary>
        /// Get the Series information that's used to get dates at a later
        /// date. This is passed into the RecurrenceHelper to get date values.
        /// Most likely used for non-ending dates.
        /// </summary>
        /// <returns></returns>
        string GetSeriesInfo()
        {
            string info;
            string endDate = "ZZZZZZZZ"; // Default for no ending date.
            string occurrences = base.NumberOfOccurrences.ToString("0000");
            string monthlyRegenType = ((int)regenType).ToString("0");
            string endDateType = ((int)base.TypeOfEndDate).ToString("0");
            string regenOnSpecificDateDayValue = regenerateOnSpecificDateDayValue.ToString("00");
            string specDatePartOne = "Z";
            string specDatePartTwo = "Z";
            string regenXMonths = regenEveryXMonths.ToString("000");

            if (specificDatePartOne != MonthlySpecificDatePartOne.NotSet)
                specDatePartOne = Convert.ToString((char)(int)(specificDatePartOne + 65));

            if (specificDatePartTwo != MonthlySpecificDatePartTwo.NotSet)
                specDatePartTwo = Convert.ToString((char)(int)(specificDatePartTwo + 65));

            string adjustValue = adjustmentValue.ToString("000");

            // If the Adjustment value is less than Zero then account for the "-"
            if (adjustmentValue < 0)
                adjustValue = adjustmentValue.ToString("00");

            // End Date may be null if no ending date.
            if (base.EndDate.HasValue)
                endDate = base.EndDate.Value.ToString("yyyyMMdd");

            // FORMATTING DEFINITIONS
            //  Y = Yearly Designator
            //  |       0 = Start Date (8 chars)
            //  |       |        1 = End Date (8 chars)
            //  |       |        |        2 = Number of occurrences (4 chars)
            //  |       |        |        |      3 = Regeneration Type (1 char)
            //  |       |        |        |      |    4 = End date type (1 char)
            //  |       |        |        |      |    |      5 = Regenerate on specific date DAY value (2 chars)
            //  |       |        |        |      |    |      |       6 = Custom Date Part One (1 char)
            //  |       |        |        |      |    |      |       |       7 = Custom Date Part Two (1 char)
            //  |       |        |        |      |    |      |       |       |       8 = Adjustment Value (3 chars)
            //  |       |        |        |      |    |      |       |       |       |     9  Regen Every x months
            //  |       |        |        |      |    |      |       |       |       |     |  
            // [0]    [1-8]    [9-16]  [17-20]  [21] [22] [23-24]  [25]    [26]    [27-29] [30-32]
            //  M   20071231  20171231   0000    1     1     00      A      A       000    000
            info = string.Format("M{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}", base.StartDate.ToString("yyyyMMdd"), endDate, occurrences, monthlyRegenType, endDateType, regenOnSpecificDateDayValue, specDatePartOne, specDatePartTwo, adjustValue, regenXMonths);
            return info;
        }


        /// <summary>
        /// Get recurring dates from a specific constant date such as 27 July.
        /// </summary>
        /// <returns></returns>
        RecurrenceValues GetSpecificDayOfMonthDates()
        {
            RecurrenceValues values = new RecurrenceValues();
            DateTime dt = base.StartDate;
            int dayValue = regenerateOnSpecificDateDayValue;
            int daysOfMonth = DateTime.DaysInMonth(dt.Year, dt.Month);
            // Get the max days of the month and make sure it's not 
            // less than the specified day value trying to be set.
            if (daysOfMonth < regenerateOnSpecificDateDayValue)
                dayValue = daysOfMonth;

            // Determine if start date is greater than the Day and Month values
            // for a specific date.
            DateTime newDate = new DateTime(dt.Year, dt.Month, dayValue);
            // Is the specific date before the start date, if so 
            // then make the specific date next month.
            if (newDate < dt)
                dt = newDate.AddMonths(1);
            else
                dt = newDate;


            if (getNextDateValue)
            {
                do
                {
                    values.AddDateValue(dt, adjustmentValue);
                    if (values.Values[values.Values.Count - 1] > nextDateValue)
                        break;

                    dt = dt.AddMonths(RegenEveryXMonths);
                    dt = GetCorrectedDate(dt);
                } while (dt <= nextDateValue.AddMonths(RegenEveryXMonths + 1)); // Ensure the last date if greater than what's needed for the next date in the cycle
            }
            else
            {
                switch (base.TypeOfEndDate)
                {
                    case EndDateType.NoEndDate:
                        throw new Exception("The ability to create recurring dates with no End date is not currently available.");

                    case EndDateType.NumberOfOccurrences:

                        for (int i = 0; i < base.NumberOfOccurrences; i++)
                        {
                            values.AddDateValue(dt, adjustmentValue);
                            dt = dt.AddMonths(RegenEveryXMonths);
                            dt = GetCorrectedDate(dt);
                        }
                        break;

                    case EndDateType.SpecificDate:
                        do
                        {
                            values.AddDateValue(dt, adjustmentValue);
                            dt = dt.AddMonths(RegenEveryXMonths);
                            dt = GetCorrectedDate(dt);
                        } while (dt <= base.EndDate);
                        break;

                    default:
                        throw new ArgumentNullException("TypeOfEndDate", "The TypeOfEndDate property has not been set.");
                }
            }

            return values;
        }

        /// <summary>
        /// Correct an input date to be equal to or less than the specified day value.
        /// </summary>
        /// <param name="input">Date to check to ensure it matches the specified day value or the max number of days for that month, whichever comes first.</param>
        /// <returns>DateTime</returns>
        DateTime GetCorrectedDate(DateTime input)
        {
            DateTime dt = input;
            // Ensure the day value hasn't changed.
            // This will occurr if the month is Feb. All
            // dates after that will have the same day.
            if (dt.Day < this.regenerateOnSpecificDateDayValue && DateTime.DaysInMonth(dt.Year, dt.Month) > dt.Day)
            {
                // The Specified day is greater than the number of days in the month.
                if (this.regenerateOnSpecificDateDayValue > DateTime.DaysInMonth(dt.Year, dt.Month))
                    dt = new DateTime(dt.Year, dt.Month, DateTime.DaysInMonth(dt.Year, dt.Month));
                else
                    // The specified date is less than number of days in month.
                    dt = new DateTime(dt.Year, dt.Month, this.regenerateOnSpecificDateDayValue);
            }
            return dt;
        }

        /// <summary>
        /// Get recurring dates from custom date such as First Sunday of July.
        /// </summary>
        /// <returns></returns>
        RecurrenceValues GetCustomDayOfMonthDates()
        {
            if (this.SpecificDatePartOne == MonthlySpecificDatePartOne.NotSet)
                throw new Exception("The First part of the custom date has not been set.");
            if (this.SpecificDatePartTwo == MonthlySpecificDatePartTwo.NotSet)
                throw new Exception("The Second part of the custom date has not been set.");

            RecurrenceValues values = new RecurrenceValues();
            DateTime dt = base.StartDate;

            // Get Next Date value only
            if (getNextDateValue)
            {
                do
                {
                    dt = GetCustomDate(dt);
                    // If the date returned is less than the start date
                    // then do it again to increment past the start date
                    if (dt < base.StartDate)
                    {
                        dt = dt.AddMonths(1);
                        dt = GetCustomDate(dt);
                    }
                    values.AddDateValue(dt, adjustmentValue);
                    if (values.Values[values.Values.Count - 1] > nextDateValue)
                        break;

                    dt = dt.AddMonths(RegenEveryXMonths);

                } while (dt <= nextDateValue.AddMonths(RegenEveryXMonths + 1)); // Ensure the last date if greater than what's needed for the next date in the cycle
            }
            else
            {
                switch (base.TypeOfEndDate)
                {
                    case EndDateType.NoEndDate:
                        throw new Exception("The ability to create recurring dates with no End date is not currently available.");

                    case EndDateType.NumberOfOccurrences:
                        for (int i = 0; i < base.NumberOfOccurrences; i++)
                        {
                            dt = GetCustomDate(dt);
                            // If the date returned is less than the start date
                            // then do it again to increment past the start date
                            if (dt < base.StartDate)
                            {
                                dt = dt.AddMonths(1);
                                dt = GetCustomDate(dt);
                            }
                            values.AddDateValue(dt, adjustmentValue);
                            dt = dt.AddMonths(RegenEveryXMonths);
                        }
                        break;

                    case EndDateType.SpecificDate:
                        do
                        {
                            dt = GetCustomDate(dt);
                            // If the date returned is less than the start date
                            // then do it again to increment past the start date
                            if (dt < base.StartDate)
                            {
                                dt = dt.AddMonths(1);
                                dt = GetCustomDate(dt);
                            }
                            values.AddDateValue(dt, adjustmentValue);
                            dt = dt.AddMonths(RegenEveryXMonths);
                        } while (dt <= base.EndDate);
                        break;

                    default:
                        throw new ArgumentNullException("TypeOfEndDate", "The TypeOfEndDate property has not been set.");
                }
            }
            return values;

        }

        /// <summary>
        /// Get the custom value from the 1st, 2nd, and 3rd custom date parts
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        DateTime GetCustomDate(DateTime currentDate)
        {
            int year = currentDate.Year;
            DateTime dt = new DateTime(year, currentDate.Month, 1);
            int day = 1;
            int firstPart = (int)SpecificDatePartOne + 1;
            int daysOfMonth = DateTime.DaysInMonth(year, dt.Month);

            switch (SpecificDatePartTwo)
            {
                case MonthlySpecificDatePartTwo.Day:
                    // If only getting the Last day of the month
                    if (SpecificDatePartOne == MonthlySpecificDatePartOne.Last)
                        dt = new DateTime(year, dt.Month, DateTime.DaysInMonth(year, dt.Month));
                    else
                        // Get a specific day of the month such as First, Second, Third, Fourth
                        dt = new DateTime(year, dt.Month, firstPart);

                    break;

                case MonthlySpecificDatePartTwo.Weekday:
                    int weekDayCount = 0;
                    DateTime lastWeekday = dt;
                    do
                    {
                        // Check for anything other than Saturday and Sunday
                        if (dt.DayOfWeek != DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday)
                        {
                            // Get a specific Weekday of the Month
                            if (SpecificDatePartOne != MonthlySpecificDatePartOne.Last)
                            {
                                // Add up the weekday count
                                weekDayCount++;
                                // If the current weekday count matches then exit
                                if (weekDayCount == firstPart)
                                    break;
                            }
                            else
                            {
                                // Get the last weekday of the month
                                lastWeekday = dt;
                            }
                        }
                        dt = dt.AddDays(1);
                        day++;
                    } while (day <= daysOfMonth);

                    // If getting the last weekday of the month then 
                    // set the returning value to the last weekday found.
                    if (SpecificDatePartOne == MonthlySpecificDatePartOne.Last)
                        dt = lastWeekday;

                    break;

                case MonthlySpecificDatePartTwo.WeekendDay:
                    int weekendDayCount = 0;
                    DateTime lastWeekendday = dt;
                    do
                    {
                        // Check for anything other than Saturday and Sunday
                        if (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
                        {
                            // Get a specific Weekday of the Month
                            if (SpecificDatePartOne != MonthlySpecificDatePartOne.Last)
                            {
                                // Add up the weekday count
                                weekendDayCount++;
                                // If the current weekday count matches then exit
                                if (weekendDayCount == firstPart)
                                    break;
                            }
                            else
                            {
                                // Get the last weekday of the month
                                lastWeekendday = dt;
                            }
                        }
                        dt = dt.AddDays(1);
                        day++;
                    } while (day <= daysOfMonth);

                    // If getting the last weekday of the month then 
                    // set the returning value to the last weekday found.
                    if (SpecificDatePartOne == MonthlySpecificDatePartOne.Last)
                        dt = lastWeekendday;

                    break;

                case MonthlySpecificDatePartTwo.Monday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Monday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Tuesday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Tuesday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Wednesday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Wednesday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Thursday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Thursday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Friday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Friday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Saturday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Saturday, daysOfMonth, firstPart);
                    break;

                case MonthlySpecificDatePartTwo.Sunday:
                    dt = GetCustomWeekday(dt, DayOfWeek.Sunday, daysOfMonth, firstPart);
                    break;
            }
            return dt;
        }

        DateTime GetCustomWeekday(DateTime startDate, DayOfWeek weekDay, int daysOfMonth, int firstDatePart)
        {
            int day = 1;
            int dayCount = 0;
            DateTime lastDOW = startDate;
            DateTime returnDate = startDate;
            do
            {
                // Check for day of the week
                if (returnDate.DayOfWeek == weekDay)
                {
                    // Get a specific Weekday of the Month
                    if (SpecificDatePartOne != MonthlySpecificDatePartOne.Last)
                    {
                        // Add up the days found count
                        dayCount++;
                        // If the current weekday count matches then exit
                        if (dayCount == firstDatePart)
                        {
                            break;
                        }
                    }
                    else
                    {
                        // Get the current date value
                        lastDOW = returnDate;
                    }
                }
                returnDate = returnDate.AddDays(1);
                day++;
            } while (day <= daysOfMonth);

            // If getting the last weekday of the month then 
            // set the returning value to the last weekday found.
            if (SpecificDatePartOne == MonthlySpecificDatePartOne.Last)
                returnDate = lastDOW;

            return returnDate;
        }
        #endregion //Private Procedures

        /// <summary>
        ///     Get a user-friendly class that is a easy way using Properties that define the Series Info
        /// </summary>
        /// <param name="seriesInfo" type="string">
        ///     <para>
        ///         String of Series Info that was first generated by this MonthlyRecurrenceSettings Class object.
        ///     </para>
        /// </param>
        /// <returns>
        ///     A RecurrenceGenerator.RecurrenceInfo value...
        /// </returns>
        internal static RecurrenceInfo GetFriendlyRecurrenceInfo(string seriesInfo)
        {
            RecurrenceInfo info = new RecurrenceInfo();
            EndDateType endType = EndDateType.NotDefined;
            DateTime endDateValue = DateTime.MinValue;
            int noOccurrences;

            // Exit if not a Monthly seriesInfo type
            if (!seriesInfo.StartsWith("M"))
                return null;

            info.SetSeriesInfo(seriesInfo);
            info.SetRecurrenceType(RecurrenceType.Monthly);
            // FORMATTING DEFINITIONS
            //  Y = Yearly Designator
            //  |       0 = Start Date (8 chars)
            //  |       |        1 = End Date (8 chars)
            //  |       |        |        2 = Number of occurrences (4 chars)
            //  |       |        |        |      3 = Regeneration Type (1 char)
            //  |       |        |        |      |    4 = End date type (1 char)
            //  |       |        |        |      |    |      5 = Regenerate on specific date DAY value (2 chars)
            //  |       |        |        |      |    |      |       6 = Custom Date Part One (1 char)
            //  |       |        |        |      |    |      |       |       7 = Custom Date Part Two (1 char)
            //  |       |        |        |      |    |      |       |       |       8 = Adjustment Value (3 chars)
            //  |       |        |        |      |    |      |       |       |       |     9  Regen Every x months
            //  |       |        |        |      |    |      |       |       |       |     |  
            // [0]    [1-8]    [9-16]  [17-20]  [21] [22] [23-24]  [25]    [26]    [27-29] [30-32]
            //  M   01082007  20171231   0000    1     1     00      A      A       000    000
            string startDate = seriesInfo.Substring(1, 8);

            DateTime dtStartDate = new DateTime(int.Parse(startDate.Substring(0, 4)), int.Parse(startDate.Substring(4, 2)), int.Parse(startDate.Substring(6, 2)));
            string endDate = seriesInfo.Substring(9, 8);

            string occurrences = seriesInfo.Substring(17, 4);
            string monthlyRegenType = seriesInfo.Substring(21, 1);
            string endDateType = seriesInfo.Substring(22, 1);
            string regenOnSpecificDateDayValue = seriesInfo.Substring(23, 2);
            string specDatePartOne = seriesInfo.Substring(25, 1);
            string specDatePartTwo = seriesInfo.Substring(26, 1);
            string adjustValue = seriesInfo.Substring(27, 3);
            int regenXMonths = int.Parse(seriesInfo.Substring(30, 3));
            endType = (EndDateType)(int.Parse(endDateType));
            noOccurrences = int.Parse(occurrences);

            MonthlySpecificDatePartOne partOne = MonthlySpecificDatePartOne.NotSet;
            MonthlySpecificDatePartTwo partTwo = MonthlySpecificDatePartTwo.NotSet;

            if (specDatePartOne == "Z")
                partOne = MonthlySpecificDatePartOne.NotSet;
            else
                partOne = (MonthlySpecificDatePartOne)(Convert.ToInt32(specDatePartOne[0]) - 65);

            if (specDatePartTwo == "Z")
                partTwo = MonthlySpecificDatePartTwo.NotSet;
            else
                partTwo = (MonthlySpecificDatePartTwo)(Convert.ToInt32(specDatePartTwo[0]) - 65);

            endType = (EndDateType)(int.Parse(endDateType));
            noOccurrences = int.Parse(occurrences);

            // Get the EndDate before any modifications on it are performed
            if (endType == EndDateType.SpecificDate)
                endDateValue = new DateTime(int.Parse(endDate.Substring(0, 4)), int.Parse(endDate.Substring(4, 2)), int.Parse(endDate.Substring(6, 2)));

            info.SetEndDateType(endType);
            // Determine the Constructor by the type of End Date.
            // All constructors start with a Start date at a minimum.
            switch (endType)
            {
                case EndDateType.NumberOfOccurrences:
                    info.SetStartDate(dtStartDate);
                    info.SetNumberOfOccurrences(noOccurrences);
                    break;

                case EndDateType.SpecificDate:
                    info.SetStartDate(dtStartDate);
                    info.SetEndDate(endDateValue);
                    break;

                case EndDateType.NoEndDate:
                    info.SetStartDate(dtStartDate);
                    break;
            }

            // Set the adjusted values
            info.SetAdjustmentValue(Convert.ToInt32(adjustValue));
            info.SetMonthlyRegenType((MonthlyRegenType)(int.Parse(monthlyRegenType)));

            // Determine the Type of dates to get, specific, custom, etc.
            switch (info.MonthlyRegenType)
            {
                case MonthlyRegenType.OnSpecificDayOfMonth:
                    info.SetMonthlyRegenerateOnSpecificDateDayValue(int.Parse(regenOnSpecificDateDayValue));
                    info.SetRegenEveryXMonths(regenXMonths);
                    break;

                case MonthlyRegenType.OnCustomDateFormat:
                    info.SetMonthlySpecificDatePartOne(partOne);
                    info.SetMonthlySpecificDatePartTwo(partTwo);
                    info.SetRegenEveryXMonths(regenXMonths);
                    break;

                case MonthlyRegenType.AfterOccurrenceCompleted:

                    break;
            }

            return info;
        }

        #region Public GetValues
        /// <summary>
        /// Get Custom dates such as Last Saturday of the month with option as to the increment of every x-months.
        /// </summary>
        /// <param name="customDatePartOne">Corresponds to Part of month such as First, Last.</param>
        /// <param name="customDatePartTwo">Corresponds to day of the week to get such as Tuesday or Weekend Day.</param>
        /// <param name="regenEveryXMonths">How many months to skip, such as 2 for every other month.</param>
        /// <returns></returns>
        public RecurrenceValues GetValues(MonthlySpecificDatePartOne customDatePartOne, MonthlySpecificDatePartTwo customDatePartTwo, int regenEveryXMonths)
        {
            this.regenEveryXMonths = regenEveryXMonths;
            specificDatePartOne = customDatePartOne;
            specificDatePartTwo = customDatePartTwo;
            regenType = MonthlyRegenType.OnCustomDateFormat;
            return GetValues();
        }

        /// <summary>
        /// Get values for a specific day of the month. Eg. Every 23rd day. With option to get every x-month.
        /// </summary>
        /// <param name="dayOfMonthToRegen">Day of month you want to set as the value to get from month to month.</param>
        /// <param name="regenEveryXMonths">How many months to skip, such as 2 for every other month.</param>
        /// <returns></returns>
        public RecurrenceValues GetValues(int dayOfMonthToRegen, int regenEveryXMonths)
        {
            this.regenEveryXMonths = regenEveryXMonths;
            regenerateOnSpecificDateDayValue = dayOfMonthToRegen;
            regenType = MonthlyRegenType.OnSpecificDayOfMonth;
            return GetValues();
        }
#endregion //Public GetValues

        #region Public Fields
        /// <summary>
        /// What is the first part to the Custom date such as First, Last.
        /// </summary>
        public MonthlySpecificDatePartOne SpecificDatePartOne
        {
            get
            {
                return specificDatePartOne;
            }
        }

        /// <summary>
        /// What is the second part to the Custom date such as which weekday, weekend day, etc.
        /// </summary>
        public MonthlySpecificDatePartTwo SpecificDatePartTwo
        {
            get
            {
                return specificDatePartTwo;
            }
        }

        /// <summary>
        /// What is the regeneration type such as Specific day of month, custom date, etc.
        /// </summary>
        public MonthlyRegenType RegenType
        {
            get
            {
                return regenType;
            }
        }

        /// <summary>
        ///  Day of month to regenerate when RegenType = specific day of month.
        /// </summary>
        public int RegenerateOnSpecificDateDayValue
        {
            get
            {
                return regenerateOnSpecificDateDayValue;
            }
        }

        /// <summary>
        /// Used to adjust the date plus/minus x-days
        /// </summary>
        public int AdjustmentValue
        {
            get
            {
                return adjustmentValue;
            }
            set
            {
                adjustmentValue = value;
            }
        }
        /// <summary>
        /// What is the interval to generate dates. This is used to skip months in the cycle.
        /// </summary>
        public int RegenEveryXMonths
        {
            get
            {
                return regenEveryXMonths;
            }
        }
        #endregion //Public Fields

        #region Internal GetValues
        /// <summary>
        ///      Final overloaded function that gets the Recurrence Values. 
        ///      This is called from the RecurrenceHelper staic methods only.
        /// </summary>
        /// <returns>
        ///     A RecurrenceGenerator.RecurrenceValues value...
        /// </returns>
        internal override RecurrenceValues GetValues()
        {
            return GetRecurrenceValues();
        }
        internal override RecurrenceValues GetValues(DateTime startDate, DateTime endDate)
        {
            base.StartDate = startDate;
            base.EndDate = endDate;
            // Change the end type to End Date as this original series info
            // may have been set to number of occurrences.
            base.endDateType = EndDateType.SpecificDate;
            return GetRecurrenceValues();
        }

        internal override RecurrenceValues GetValues(DateTime startDate, int numberOfOccurrences)
        {
            base.NumberOfOccurrences = numberOfOccurrences;
            base.StartDate = startDate;
            // Change the end type to number of occurrences. 
            // This must be set because the original starting Series Info may
            // be set to have an End Date type.
            base.endDateType = EndDateType.NumberOfOccurrences;
            return GetRecurrenceValues();
        }

        RecurrenceValues GetRecurrenceValues()
        {
            RecurrenceValues values = null;
            switch (RegenType)
            {
                case MonthlyRegenType.OnSpecificDayOfMonth:
                    values = GetSpecificDayOfMonthDates();
                    break;

                case MonthlyRegenType.OnCustomDateFormat:
                    values = GetCustomDayOfMonthDates();
                    break;

                case MonthlyRegenType.AfterOccurrenceCompleted:

                    break;

            }
            if (values.Values.Count > 0)
            {
                values.SetStartDate(values.Values[0]);

                // Get the end date if not open-ended
                if (base.TypeOfEndDate != EndDateType.NoEndDate)
                    values.SetEndDate(values.Values[values.Values.Count - 1]);
            }

            // Set the Series information that's used to get the next date
            // values for no ending dates.
            values.SetSeriesInfo(GetSeriesInfo());

            return values;
        }
#endregion //Internal GetValues
        
        #region Internal Procedures
        internal static string GetPatternDefinition(string seriesInfo)
        {
            string returnValue = string.Empty;
            returnValue =
            " MONTHLY FORMATTING DEFINITIONS\r\n" +
            "  Y = Yearly Designator\r\n" +
            "  |       0 = Start Date (8 chars)\r\n" +
            "  |       |        1 = End Date (8 chars)\r\n" +
            "  |       |        |        2 = Number of occurrences (4 chars)\r\n" +
            "  |       |        |        |      3 = Regeneration Type (1 char)\r\n" +
            "  |       |        |        |      |    4 = End date type (1 char)\r\n" +
            "  |       |        |        |      |    |      5 = Regenerate on specific date DAY value (2 chars)\r\n" +
            "  |       |        |        |      |    |      |       6 = Custom Date Part One (1 char)\r\n" +
            "  |       |        |        |      |    |      |       |       7 = Custom Date Part Two (1 char)\r\n" +
            "  |       |        |        |      |    |      |       |       |       8 = Adjustment Value (3 chars)\r\n" +
            "  |       |        |        |      |    |      |       |       |       |     9  Regen Every x months\r\n" +
            "  |       |        |        |      |    |      |       |       |       |     |  \r\n" +
            " [0]    [1-8]    [9-16]  [17-20]  [21] [22] [23-24]  [25]    [26]    [27-29] [30-32]\r\n" +
            string.Format("  M    {0} {1}  {2}     {3}    {4}     {5}      {6}       {7}        {8}     {9}\r\n", seriesInfo.Substring(1, 8), seriesInfo.Substring(9, 8), seriesInfo.Substring(17, 4), seriesInfo.Substring(21, 1), seriesInfo.Substring(22, 1), seriesInfo.Substring(23, 2), seriesInfo.Substring(25, 1), seriesInfo.Substring(26, 1), seriesInfo.Substring(27, 3), seriesInfo.Substring(30, 3));

            return returnValue;
        }

        void SetValues(MonthlySpecificDatePartOne customDatePartOne, MonthlySpecificDatePartTwo customDatePartTwo, int regenEveryXMonths)
        {
            this.regenEveryXMonths = regenEveryXMonths;
            specificDatePartOne = customDatePartOne;
            specificDatePartTwo = customDatePartTwo;
            regenType = MonthlyRegenType.OnCustomDateFormat;
        }

        void SetValues(int dayOfMonthToRegen, int regenEveryXMonths)
        {
            this.regenEveryXMonths = regenEveryXMonths;
            regenerateOnSpecificDateDayValue = dayOfMonthToRegen;
            regenType = MonthlyRegenType.OnSpecificDayOfMonth;
        }


        internal override DateTime GetNextDate(DateTime currentDate)
        {
            getNextDateValue = true;
            nextDateValue = currentDate;
            // Now get the values and return the last date found.
            RecurrenceValues values = GetValues();
            return values.EndDate;
        }

        internal static MonthlyRecurrenceSettings GetRecurrenceSettings(string seriesInfo)
        {
            return GetRecurrenceSettings(seriesInfo, -1, DateTime.MinValue);
        }

        internal static MonthlyRecurrenceSettings GetRecurrenceSettings(string seriesInfo, int modifiedOccurrencesValue)
        {
            return GetRecurrenceSettings(seriesInfo, modifiedOccurrencesValue, DateTime.MinValue);
        }

        internal static MonthlyRecurrenceSettings GetRecurrenceSettings(string seriesInfo, DateTime modifiedEndDate)
        {
            return GetRecurrenceSettings(seriesInfo, -1, modifiedEndDate);
        }

        static MonthlyRecurrenceSettings GetRecurrenceSettings(string seriesInfo, int modifiedOccurrencesValue, DateTime modifiedEndDate)
        {
            // Get the Recurrence Info object. This makes it easy to work with existing series of date patterns.
            RecurrenceInfo info = MonthlyRecurrenceSettings.GetFriendlyRecurrenceInfo(seriesInfo);
            MonthlyRecurrenceSettings settings = null;

            // Check to see if this is to modify the SeriesInfo and run as endtype for occurrences
            if (modifiedOccurrencesValue != -1)
            {
                info.SetEndDateType(EndDateType.NumberOfOccurrences);
                info.SetNumberOfOccurrences(modifiedOccurrencesValue);
            }
            // Check to see if this is to modify the EndDate and run as endType for EndDate
            if (modifiedEndDate != DateTime.MinValue)
            {
                info.SetEndDateType(EndDateType.SpecificDate);
                info.SetEndDate(modifiedEndDate);
            }

            // Determine the Constructor by the type of End Date.
            // All constructors start with a Start date at a minimum.
            switch (info.EndDateType)
            {
                case EndDateType.NumberOfOccurrences:
                    settings = new MonthlyRecurrenceSettings(info.StartDate, info.NumberOfOccurrences);
                    break;

                case EndDateType.SpecificDate:
                    settings = new MonthlyRecurrenceSettings(info.StartDate, info.EndDate.Value);
                    break;

                case EndDateType.NoEndDate:
                    settings = new MonthlyRecurrenceSettings(info.StartDate);
                    break;
            }

            settings.AdjustmentValue = info.AdjustmentValue;

            // Determine the Type of dates to get, specific, custom, etc.
            switch (info.MonthlyRegenType)
            {
                case MonthlyRegenType.OnSpecificDayOfMonth:
                    settings.SetValues(info.MonthlyRegenerateOnSpecificDateDayValue, info.MonthlyRegenEveryXMonths);
                    break;

                case MonthlyRegenType.OnCustomDateFormat:
                    settings.SetValues(info.MonthlySpecificDatePartOne, info.MonthlySpecificDatePartTwo, info.MonthlyRegenEveryXMonths);
                    break;

                case MonthlyRegenType.AfterOccurrenceCompleted:

                    break;
            }

            return settings;
        }
#endregion //Internal Procedures

        
        

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) BOCA Software Technologies, Inc.
United States United States
.NET Developer in Garner, North Carolina. Specializing in WinForms development in C#, VB.Net.

CEO/Founder BOCA Software Technologies, Inc.

Comments and Discussions