Extract Calendar data from Outlook into Excel


August 10, 2008 – 9:15 am by JP

    I completed some VBA code that will allow you to export appointment information (meetings, appointments) from Outlook into Excel. It requires a reference to the Outlook object library (unless you care to reengineer it), but it works even with Outlook closed. I think you'll find it very useful for when you need to examine or manipulate Outlook Calendar data, and want something a bit faster (and more flexible) than Outlook's built-in exporter.

    The code begins by setting a reference to the Outlook Application object, which, depending on whether Outlook is open or not, can take up to 10 seconds, so I strongly recommend you have Outlook open when you run this code. Then we reference the default Calendar folder and filter out the items based on dates passed as arguments to the sub.

    Because recurring appointments can potentially have an unlimited number of recurrences (when the organizer does not specify an End Date), we use the Restrict method to limit the number of calendar entries we need to return to only those that fall between 12 AM on the start date and 11:59 PM on the end date.

    Be careful with the Restrict method, however; if you use it in an Exchange environment, it can slow down Outlook's performance.

VBA:
  1. Private Sub GetCalData(StartDate As Date, Optional EndDate As Date)
  2.  
  3. ' -------------------------------------------------
  4. ' Notes:
  5. ' If Outlook is not open, it still works, but much slower (~8 secs vs. 2 secs w/ Outlook open).
  6. ' Make sure to reference the Outlook object library before running the code
  7. ' End Date is optional, if you want to pull from only one day, use: Call GetCalData("7/14/2008")
  8. ' -------------------------------------------------
  9.  
  10. Dim olApp As Outlook.Application
  11. Dim olNS As Outlook.Namespace
  12. Dim myCalItems As Outlook.Items
  13. Dim ItemstoCheck As Outlook.Items
  14. Dim ThisAppt As Outlook.AppointmentItem
  15.  
  16. Dim MyItem As Object
  17.  
  18. Dim StringToCheck As String
  19.  
  20. Dim MyBook As Excel.Workbook
  21. Dim rngStart As Excel.Range
  22.  
  23. Dim i As Long
  24. Dim NextRow As Long
  25.  
  26. ' if no end date was specified, then the requestor only wants one day, so set EndDate = StartDate
  27. ' this will let us return appts from multiple dates, if the requestor does in fact set an appropriate end date
  28. If EndDate = "12:00:00 AM" Then
  29.   EndDate = StartDate
  30. End If
  31.  
  32. If EndDate <StartDate Then
  33.   MsgBox "Those dates seem switched, please check them and try again.", vbInformation
  34.   GoTo ExitProc
  35. End If
  36.  
  37. If EndDate - StartDate> 28 Then
  38.   ' ask if the requestor wants so much info
  39.   If MsgBox("This could take some time. Continue anyway?", vbInformation + vbYesNo) = vbNo Then
  40.       GoTo ExitProc
  41.   End If
  42. End If
  43.  
  44. ' get or create Outlook object and make sure it exists before continuing
  45. On Error Resume Next
  46.   Set olApp = GetObject(, "Outlook.Application")
  47.   If Err.Number <> 0 Then
  48.     Set olApp = CreateObject("Outlook.Application")
  49.   End If
  50. On Error GoTo 0
  51. If olApp Is Nothing Then
  52.   MsgBox "Cannot start Outlook.", vbExclamation
  53.   GoTo ExitProc
  54. End If
  55.  
  56. Set olNS = olApp.GetNamespace("MAPI")
  57. Set myCalItems = olNS.GetDefaultFolder(olFolderCalendar).Items
  58.  
  59. ' ------------------------------------------------------------------
  60. ' the following code adapted from:
  61. ' http://www.outlookcode.com/article.aspx?id=30
  62. '
  63. With myCalItems
  64.   .Sort "[Start]", False
  65.   .IncludeRecurrences = True
  66. End With
  67. '
  68. StringToCheck = "[Start]>= " & Quote(StartDate & " 12:00 AM") & " AND [End] <= " & _
  69.   Quote(EndDate & " 11:59 PM")
  70. Debug.Print StringToCheck
  71. '
  72. Set ItemstoCheck = myCalItems.Restrict(StringToCheck)
  73. Debug.Print ItemstoCheck.Count
  74. ' ------------------------------------------------------------------
  75.  
  76. If ItemstoCheck.Count> 0 Then
  77.   ' we found at least one appt
  78.   ' check if there are actually any items in the collection, otherwise exit
  79.   If ItemstoCheck.Item(1) Is Nothing Then GoTo ExitProc
  80.  
  81.   Set MyBook = Excel.Workbooks.Add
  82.   Set rngStart = MyBook.Sheets(1).Range("A1")
  83.        
  84.   With rngStart
  85.     .Offset(0, 0).Value = "Subject"
  86.     .Offset(0, 1).Value = "Start Date"
  87.     .Offset(0, 2).Value = "Start Time"
  88.     .Offset(0, 3).Value = "End Date"
  89.     .Offset(0, 4).Value = "End Time"
  90.     .Offset(0, 5).Value = "Location"
  91.     .Offset(0, 6).Value = "Categories"
  92.   End With
  93.  
  94.   For Each MyItem In ItemstoCheck
  95.     If MyItem.Class = olAppointment Then
  96.     ' MyItem is the appointment or meeting item we want,
  97.     ' set obj reference to it
  98.       Set ThisAppt = MyItem
  99.       NextRow = WorksheetFunction.CountA(Range("A:A"))
  100.            
  101.       With rngStart
  102.         .End(xlDown).End(xlUp).Offset(NextRow, 0).Value = ThisAppt.Subject
  103.         .End(xlDown).End(xlUp).Offset(NextRow, 1).Value = Format(ThisAppt.Start, "MM/DD/YYYY")
  104.         .End(xlDown).End(xlUp).Offset(NextRow, 2).Value = Format(ThisAppt.Start, "HH:MM AM/PM")
  105.         .End(xlDown).End(xlUp).Offset(NextRow, 3).Value = Format(ThisAppt.End, "MM/DD/YYYY")
  106.         .End(xlDown).End(xlUp).Offset(NextRow, 4).Value = Format(ThisAppt.End, "HH:MM AM/PM")
  107.         .End(xlDown).End(xlUp).Offset(NextRow, 5).Value = ThisAppt.Location
  108.                    
  109.         If ThisAppt.Categories <> "" Then
  110.           .End(xlDown).End(xlUp).Offset(NextRow, 6).Value = ThisAppt.Categories
  111.         Else
  112.           .End(xlDown).End(xlUp).Offset(NextRow, 6).Value = "n/a"
  113.         End If
  114.       End With
  115.     End If
  116.   Next MyItem
  117.    
  118.   ' make it pretty
  119.   Call Cool_Colors(rngStart)
  120.  
  121. Else
  122.     MsgBox "There are no appointments or meetings during" & _
  123.       "the time you specified. Exiting now.", vbCritical
  124. End If
  125.  
  126. ExitProc:
  127. Set myCalItems = Nothing
  128. Set ItemstoCheck = Nothing
  129. Set olNS = Nothing
  130. Set olApp = Nothing
  131. Set rngStart = Nothing
  132. Set ThisAppt = Nothing
  133. End Sub

VBA:
  1. Private Function Quote(MyText)
  2. ' from Sue Mosher's excellent book "Microsoft Outlook Programming"
  3.   Quote = Chr(34) & MyText & Chr(34)
  4. End Function

VBA:
  1. Private Sub Cool_Colors(rng As Excel.Range)
  2. '
  3. ' Lt Blue BG with white letters
  4. '
  5. '
  6. With Range(rng, rng.End(xlToRight))
  7.   .Font.ColorIndex = 2
  8.   .Font.Bold = True
  9.   .HorizontalAlignment = xlCenter
  10.   .MergeCells = False
  11.   .AutoFilter
  12.   .CurrentRegion.Columns.AutoFit
  13.   With .Interior
  14.     .ColorIndex = 41
  15.     .Pattern = xlSolid
  16.   End With
  17. End With
  18.  
  19. End Sub

    Let's examine exactly what is going on here.

    Our sub accepts two arguments, the start date and end date. The end date is optional, in case we only want to check one day. If the end date is "12:00:00 AM", this means no end date was specified, therefore we can set the end date = start date.

    If the end date is later than the start date, the user might have made an error; we can simply exit and allow them to rerun the sub.

    After hooking the Outlook application and setting a reference to the default Calendar, we build a string used to restrict the Calendar items returned to only those that start or end within the date range arguments passed to the sub. The Restrict method has a funny way of requiring quotation marks, so using the Quote UDF from Sue Mosher's book Microsoft Outlook Programming ensures that our quotation marks will be formatted properly for the Restrict method.

    Then it's a simple matter of copying the information from each appointment to a new workbook. Notice that I hand selected certain properties to export; you can export whatever properties you want (see Outlook 2003 VBA Reference). All you need to do is update the two "With rngStart" sections.

    I exported the date and time as two separate fields, if you wanted to combine them it would be something like:

VBA:
  1. Format(ThisAppt.Start, "MM/DD/YYYY HH:MM AM/PM")
  2. Format(ThisAppt.End, "MM/DD/YYYY HH:MM AM/PM")

    To export your Calendar items, just call the main sub like this:

VBA:
  1. Sub GetApptsFromOutlook()
  2. Application.ScreenUpdating = False
  3.   Call GetCalData("7/20/2008", "8/6/2008")
  4. Application.ScreenUpdating = True
  5. End Sub

    In the spirit of modularization, I broke out the code that pretties up the header row into its own sub; we just pass the header row as a Range object.

    One minor issue we have to deal with is if there are no appointments, the code runs all the way to the For loop (after we have already populated the header row of the new worksheet) and then exits. This is because ItemstoCheck.Count returns 2147483647 (not 0), even if the date range we specified contains no appointments (based on my experiments). So if we pick a date range with no appointments, we'll end up with a useless blank spreadsheet with a populated header row.

    The way we solve this problem is to add a line that checks to see if there are any actual objects found by the Restrict method, and exits if there's really nothing there. This line does just that.

VBA:
  1. If ItemstoCheck.Item(1) Is Nothing Then GoTo ExitProc

    Here is a sample of the finished product.

Export Calendar Data Screenshot
(click to view larger image)

Enjoy,
JP


Share and Enjoy:
  • StumbleUpon
  • Technorati
  • Digg
  • Google
  • del.icio.us
  • MisterWong

Print This Post Print This Post  |  Email This Post Email This Post  |  Permalink  |  Subscribe to this feed Subscribe now!

Filed Under: Excel, Outlook, VBA, automation
Tags: , , ,

This post has 1,028 views since August 10, 2008 – 9:15 am.
  1. 4 Responses to “Extract Calendar data from Outlook into Excel”

  2. What can be done to pass variables to the Start and End Dates so that we don't have to update the Sub each and every time we want to change the dates?

    I'm pretty novice at this stuff. I've tried passing variables via a Range with the date and input boxes

    By Ryan on Aug 11, 2008

  3. Hey Ryan,

    The sub is designed so you can change the start and end dates as needed.

    Sub GetApptsFromOutlook()
    Application.ScreenUpdating = False
    Call GetCalData("7/20/2008", "8/6/2008")
    Application.ScreenUpdating = True
    End Sub

    Just change the two arguments (dates) as needed.

    If you wanted to hard code the start and end dates, just change the first line of the sub to:

    Private Sub GetCalData()

    And you would have to add

    Const StartDate As Date = 7/20/2008
    Const EndDate As Date = 8/6/2008

    right below that.

    HTH,
    JP

    By JP on Aug 12, 2008

  4. First, I want to say thanks for making this available. I was able to get it to pull from my default calendar in about 10 minutes.

    How can I pull events from a public calendar?

    Thanks,

    Mary

    By Mary Parkhouse on Nov 6, 2008

  5. Hi Mary,

    You can try to change line 57 to point to the public folder, but more likely you'll need to use CDO.

    Although I did find a function here that might do what you want: http://www.outlookcode.com/codedetail.aspx?id=1164

    --JP

    By JP on Nov 6, 2008

Post a Comment

To post VBA code in your comment, use [VBA] tags, like this: [VBA]Code goes here[/VBA].





Subscribe without commenting

Keep Reading:

Browse Posts:


« A short exercise in modular programming || Excel User Conference Update »