A script turns your Outlook annual appointment items into task items

Recently, I heard from someone who created some annually recurring appointments—for example, to check on the next year’s holidays—and later decided to turn them into annually recurring tasks. Although you can drag an appointment to the Tasks folder to create a new task, Outlook won’t create a recurring task.

The code in Listing 1, which you can place in any Outlook VBA module, addresses the need to convert annual appointments into annual tasks. The ConvertYearlyApptToTask subroutine creates a recurring task for any annual appointment that isn’t a birthday or anniversary, then deletes the item from the Calendar folder. The subroutine runs when a user invokes it from the VBA environment or from the Macros dialog box or when some other procedure calls it. If you need a refresher course on working with dates in Outlook, see "A Primer About Dates," February 2001, InstantDoc ID 16455, and "More Fun with Dates," April 2001, InstantDoc ID 20078.

Finding Recurring Items
A one-step method to locate all yearly items in the Calendar folder doesn’t exist. Therefore, you must use an Outlook property and method that I haven’t previously explained in this column to find all recurring items, then look at each item to determine whether it occurs annually. The property, IsRecurring, is suitable for use with the Find or Restrict method. The statements at callout A return an Items collection (colRecurAppts) that contains only the recurring appointments.

To get the recurrence details for an individual appointment, the code at callout B uses the GetRecurrencePattern method to return a RecurrencePattern object. The RecurrenceType property of the RecurrencePattern object can have the value of any of six built-in Outlook constants: olRecursDaily, olRecursMonthly, olRecursMonthNth, olRecursWeekly, olRecursYearly, or olRecursYearNth. To keep things simple, the ConvertYearlyApptToTask subroutine looks only for items that occur annually on a specific date, such as April 1. Thus, the subroutine uses the olRecursYearly type. (The olRecursYearNth type covers items that occur annually on the nth weekday of a particular month—e.g., the fourth Thursday in November.)

The subroutine next looks at the text of the yearly appointment’s Subject property. If the appointment is neither a birthday nor an anniversary, the code creates a new TaskItem object and uses the value from the appointment to set the task’s Subject.

The appointment’s Start date is the first occurrence of the event. However, to set the task’s DueDate, the subroutine needs to figure out the next date the appointment will occur. The GetNextYearlyOccurrence() function takes a date, a month (number 1 to 12), and a day (number 1 to 31) as its arguments and returns the next date on which that month and day will occur. The date will be next year if the date has already passed this year or later this year if it hasn’t. After the subroutine knows when the event will next occur, it uses that date to set the DueDate, StartDate, and ReminderTime properties for the new task.

Next, the code at callout C uses the GetRecurrencePattern to get the TaskItem’s recurrence details and sets them to values derived from the appointment’s recurrence pattern. Finally, the code deletes the original appointment, completing its conversion to a recurring task.

More Fun with Dates
The GetNextYearlyOccurrence() function takes advantage of a key feature of the VBA DateSerial() function; DateSerial() never returns an invalid date. For example, the expression DateSerial(2002, 2, 29) returns the date #3/1/2002# because 2002 has no February 29.

Did you notice three more helpful functions for working with dates? Day() and Month() return the appropriate part of a date as a number between 1 and 31 and between 1 and 12, respectively. DateAdd(), the counterpart of DateDiff(), lets you increase or decrease a date by a specific amount. The basic syntax is

DateAdd(<interval>, <number>, _
  <date>)</date></number></interval>

in which interval can be any of the string values in Table 1 and number can be positive or negative, depending on whether you want a date later than (positive number) or earlier than (negative number) the date argument.