2.2.1.44.1.2 Finding Valid Recurrence Dates

The process of finding valid dates for any recurring series involves the calculation of an offset, which is the value to be subtracted from an input value (day, week, or month) to find a valid value. An input value is valid if it is congruent with the date specified by the FirstDateTime field. An offset of 0 indicates that the input value is congruent and, therefore, is valid for the recurring series.

A week or a month is specified by the date on which the week or month begins. A valid week or a valid month contains the event dates. For weekly and monthly recurring series, the offset is used to determine only valid weeks or valid months. The value of the PatternTypeSpecific field of the RecurrencePattern structure, specified in section 2.2.1.44.1, is used to determine which days within the valid week or the valid month are valid event dates.

The actual formulas used to determine valid days, weeks, or months, depend on the type of recurrence pattern (daily, weekly, or monthly/yearly) being applied, but they generally involve the following variables:

  • InputValue: The day, week, or month to be examined.

    For daily/weekly recurrences, the input value is in minutes, measured from the reference time, which is midnight January 1, 1601, for a Gregorian calendar.

    For monthly recurrences, the input value is in months, measured from the reference time.

  • FirstDateTime: The value of the FirstDateTime field, as specified in section 2.2.1.44.1. 

  • Period: The value of the Period field, as specified in section 2.2.1.44.1.

Daily Recurrence

For a daily recurrence pattern, a valid day needs to be determined. A valid day is any day on which the event occurs. The offset for a daily recurrence pattern is the number of minutes to be subtracted from an input day to find a valid day and is calculated as follows.

 offset = (InputValue – FirstDateTime) % Period

where InputValue is the day to be examined, expressed as the number of minutes elapsed from midnight January 1, 1601, to that day.

The offset will vary depending on the period (every x days). The minimum period is 1 day, so the offset will be a multiple of 1440 (number of minutes in a day) or zero if the input day is valid. If the input day is not valid, the offset is used as follows to find a valid day.

 Previous valid day = InputValue – offset
  
 Next valid day = InputValue – offset + Period

For example, given the following days (in minutes, measured from the reference time, which is midnight January 1, 1601, for a Gregorian calendar), and a recurrence pattern that starts on Day 1.

Day 0 = 0

Day 1 = 1440 minutes

Day 2 = 2880 minutes

Day 3 = 4320 minutes

...

It can be seen that an "Every 1 day" (period is 1440 * 1 = 1440) recurrence pattern is uninteresting; the offset will be 0 (zero), which indicates that every day is a valid instance. Now consider an "Every 3 days" recurrence pattern (period is 1440 * 3 = 4320) with Day 4 (5760 minutes) as the start date. In this case, the value of the FirstDateTime field is 1440 and valid instances are 4, 7, 10, 13, and so forth. If Day 9 (12960) is the input day, applying the formula results in the following evaluation, which indicates whether Day 9 is a valid instance for this recurrence pattern.

 offset = (12960 – 1440) % 4320 
        = 2880

The offset is not zero, so Day 9 is not a valid instance. The offset of 2880 minutes, or 2 days, is used to make the adjustment. Substituting the values into the formulas results in the following evaluations.

 Previous valid day = 12960 – 2880
                    = 10080
  
 Next valid day = 12960 – 2880 + 4320 
                = 14400

The resulting values indicate that Day 7 (10080 minutes) is the previous valid instance and Day 10 (14400 minutes) is the next valid instance.

Weekly Recurrence

For a weekly recurrence pattern, a valid week needs to be determined and then the value of the PatternTypeSpecific field, as specified in section 2.2.1.44.1.4, is used to determine the valid day or days within that week. A valid week is any week in which the event occurs. The offset for a weekly recurrence pattern is the number of minutes to be subtracted from an input week to find a valid week and is calculated as follows:

 offset = (InputValue – FirstDateTime) % (Period * 10080)

where InputValue is the week to be examined, expressed as the number of minutes elapsed from midnight January 1, 1601, to the beginning of that week. Note that the date of the beginning of the week depends on which of the seven days of the week is designated to be the start of a calendar week. The day on which a calendar week begins is specified by the FirstDOW field with Sunday (0x00000000) being the default.

The offset will vary depending on the period (every x weeks). The minimum period is 1 week, so the offset will be a multiple of 10080 (number of minutes in a week) or zero if the input week is valid. If the input week is not valid, the offset is used as follows to find a valid week:

 Previous valid week = InputValue – offset
  
 Next valid week = InputValue – offset + (Period * 10080)

For example, consider the recurrence pattern "Every 3 weeks" with Thursday, February 8, 1601, being the start date and Sunday being the beginning of a calendar week. In this case, the value of the FirstDateTime field is 18720 and valid weeks are the weeks of February 4, February 25, March 18, April 8, and so forth. If the input week is the week of March 11, which is Day 69 (99360 minutes), applying the formula results in the following evaluation, which indicates whether the week of March 11 is a valid week.

 offset = (99360 – 18720) % (3 * 10080)
        = 20160

The offset is not zero, so the week of March 11 is not a valid week. The offset of 20160 minutes, or 2 weeks, is used to make the adjustment. Substituting the values into the formulas results in the following evaluations:

 Previous valid week = 99360 – 20160
                     = 79200
  
 Next valid week = 99360 – 20160 + (3 * 10080)
                 = 109440

The resulting values indicate that the week of February 25 (79200 minutes, Day 55) is the previous valid week and the week of March 18 (14400 minutes, Day 76) is the next valid week. To find the valid event date within the valid week, advance to Thursday, March 1, for the week of February 25; advance to Thursday, March 22, for the week of March 18.

For a more complex recurrence pattern, additional steps might be needed to find the event dates, but the formulas for determining the offset, the previous valid week, and the next valid week are the same.

Monthly or Yearly Recurrence

For a monthly or yearly recurrence pattern, a valid month needs to be determined and then the value of the PatternTypeSpecific field, as specified in section 2.2.1.44.1.5, is used to determine the valid day or days within that month. A valid month is any month in which the event occurs. The offset for monthly/yearly recurrence pattern is the number of months to be subtracted from an input month to find a valid month and is calculated as follows:

 offset = (InputValue – FDTmonth) % Period

where InputValue is the month to be examined, expressed as the number of months elapsed from midnight January 1, 1601, to the beginning of that month and FDTmonth is the number of months elapsed from midnight January 1, 1601, to the date specified by the FirstDateTime field.

The offset will vary depending on the period (every x months). The minimum period is 1 month and the period is 12 for yearly recurrences. A yearly recurrence pattern is just a monthly pattern that occurs every 12 months. The offset is zero if the input month is valid. If the input month is not valid, the offset is used as follows to find a valid month:

 Previous valid month = InputValue – offset
  
 Next valid month = InputValue – offset + Period

For example, consider the recurrence pattern "Every 5 months on the 19th of the month" with April 19, 2008, being the start date. In this case, the value of the FirstDateTime field is 84960, corresponding to March 1, 1601 (the very first valid month for this recurrence pattern, dating back to January 1, 1601). There are 2 months between midnight January 1, 1601, and March 1, 1601, so the value of FTDmonth is 2. The valid months are April and September of 2008, February, July, and December of 2009, and so forth. If the input month is November 2009, which is 4906 months from midnight January 1, 1601, applying the formula results in the following evaluation, which indicates whether November 2009 is a valid month.

 offset = (4906 – 2) % 5
        = 4

The offset is not zero, so November 2009 is not a valid month. The offset of 4 months is used to make the adjustment. Substituting the values into the formulas results in the following evaluations:

 Previous valid month = 4906 – 4
                      = 4902
  
 Next valid month = 4906 – 4 + 5
                  = 4907

The resulting values indicate that July 2009 is the previous valid month and December 2009 is the next valid month. To find the valid event date within the valid month, advance to 19th of the month.

For a more complex recurrence pattern, additional steps might be needed to find the valid event dates, but the formulas for determining the offset, the previous valid month, and the next valid month are the same. A non-Gregorian calendar presents additional challenges, such as leap months.