Birthday Calendar: Address Book/iCal Integration

I don't know why, but it turns out that most of my friends' birthdays are in December. It those few scattered about the rest of the year I have trouble remembering, and I can't count on my Macs' support: although I diligently add everyone's birthday to Address Book, iCal doesn't bother to incorporate them into my calendar.

This lack of integration – otherwise an Apple strong-point – annoyed me initially, but I forgot about it until the end of 2003. The GNOME project (the beginnings of a desktop for non-Mac Unixes) offered cash prizes ('bounties') for people who solved a variety of problems with their applications, including automatically adding address-book birthday entries into the calendar.

Rather than switch to Linux, where the only decent application is Mozilla Firefox, I thought I'd knock up something similar for Mac OS. What I didn't know was that iCal doesn't have any kind of API.

Talking to iCal
If you look inside ~/Library/Calendars, you'll see a file for each of your iCal calendars. If a new file is written to that directory, iCal will notice next time it starts, and add it to its list of calendars.

You can open these .ics files with any text editor; do so, and you'll see that they're in a simple documented IETF standard format [http://www.imc.org/ietf-calendar/index.html].

The macdevcenter.com article "Transforming iCal Calendars with Java" made me want to use Ruby, my scripting language of choice, because Java – though my heavy-duty programming language of choice – seemed such an ill fit for this kind of work. What I wanted was a simple little script that would read my Address Book database, and write out a calendar file for iCal.

Talking to Address Book
If the annoying thing about iCal was its lack of an API, the annoying thing about Address Book is that it has an API instead of using a documented text-based format for its database.

A macdevcenter.com article from 2002, "A Look Inside Address Book" showed how to use the AddressBook framework from Objective C to iterate through all the people in your address book. The only odd omission from the API is a way to get an ABPerson's full name in the preferred form. For my purposes, I made do with the concatenation of the kABFirstNameProperty and the kABLastNameProperty.

Oh no, not Objective C!
I'm deeply ambivalent about Objective C. I really like Cocoa: it's the best application-building framework I've ever used, by some margin. I really like Objective C's method invocation syntax, something which seems to be a sticking point for many. But the thought of going back to manual memory management in the 21st century is almost too much to bear. That, and Objective C's tendency to degenerate into very K&R-like C when Cocoa doesn't just do it all for you tends to put me off. In actual fact, Objective C isn't as bad as some of its users would mislead you into believing. You can declare variables mid-block, for example. You can use enum instead of #define. But it's still quite primitive.

As for Objective C++, you've probably heard of it, but it's not something you see every day, and it seems pretty much undocumented. As a C++ programmer by day, Objective C++ sounded much more tempting than Objective C, so to make up for not being able to use Ruby, I decided to give Objective C++ a go.

Using Objective C++ turns out to be as simple as naming your source file with a .mm suffix instead of Objective C's .m, and making sure you use g++ rather than gcc for the link step. If you use gcc, it won't link with the C++ library, and you'll get this link error:

ld: Undefined symbols:

This program doesn't make heavy use of C++ features. I use std::ostream for output, in case some day I want to write output directly to a file, say. I overload operator<< for NSDate* and NSString* so that I only have to say once what format I want them output in. And that's more-or-less it.

Here's the code:

#import <AddressBook/AddressBook.h>
#import <Foundation/Foundation.h>
#import <iostream>

void emitHeader(std::ostream& os) {
<< "VERSION:2.0\n"
<< "X-WR-CALNAME:Birthdays\n"

void emitFooter(std::ostream& os) {
os << "END:VCALENDAR\n";

NSDate* dayAfter(NSDate* initialDay) {
static const NSTimeInterval SECONDS_PER_DAY = 60 * 60 * 24;
NSTimeInterval initial = [initialDay timeIntervalSince1970];
NSTimeInterval interval = initial + SECONDS_PER_DAY;
return [NSDate dateWithTimeIntervalSince1970: interval];

void emitAlarm(std::ostream& os) {
os << "BEGIN:VALARM\n"
<< "TRIGGER:-P3D\n"
<< "DESCRIPTION:Event reminder\n"
<< "END:VALARM\n";

std::ostream& operator<<(std::ostream& os, NSString* string) {
return os << [string UTF8String];

std::ostream& operator<<(std::ostream& os, NSDate* date) {
NSString* string = [date descriptionWithCalendarFormat: @"%Y%m%d"
timeZone: nil
locale: nil];
return os << string;

void emitSummary(std::ostream& os, ABPerson* person) {
NSString* firstName = [person valueForProperty: kABFirstNameProperty];
NSString* lastName = [person valueForProperty: kABLastNameProperty];
os << "SUMMARY:" << firstName << " " << lastName << "'s Birthday\n";

void emitBirthdayEvent(std::ostream& os, ABPerson* person) {
NSDate* birthday = [person valueForProperty: kABBirthdayProperty];
if (birthday == nil) {

os << "BEGIN:VEVENT\n"
<< "DTSTART;VALUE=DATE:" << birthday << "\n"
<< "DTEND;VALUE=DATE:" << dayAfter(birthday) << "\n";
emitSummary(os, person);
os << "END:VEVENT\n";

void emitBirthdayEvents(std::ostream& os) {
NSArray* people = [[ABAddressBook sharedAddressBook] people];
for (size_t i = 0; i < [people count]; ++i) {
emitBirthdayEvent(os, [people objectAtIndex: i]);

int main(int /*argc*/, char* /*argv*/[]) {
id pool = [[NSAutoreleasePool alloc] init];
[pool release];
return 0;

You can run this from cron(1), but you need to quit iCal before writing the output to ~/Library/Calendars/Birthdays.ics if you want to be sure iCal won't overwrite it. You'll also probably need to click on the calendar in the Calendars list before the events appear on the Day/Week/Month view. iCal's actually got worse in this respect since I started using it.

Objective C++
As it turns out, there are some unfortunate limits to what you can do with Objective C++. You can't have non-POD members in an Objective C class, for example. If you try, the compiler will warn that the constructor and destructor won't get called. So if you thought you could use std::string to avoid writing getters and setters for NSString* ivars, think again. You can forget trying to encapsulate the recommended boilerplate for getters and setters in a template class, too, because not having your constructor and destructor called throw quite a spanner in the works. Hopefully this is a restriction that will be lifted some day. Destructors are easily C++'s best feature.

What's the cost to using Objective C++ instead of Objective C? Why doesn't everyone, if C++ is a superset of C? The main cost I've noticed is the large increase in compile time. If you've ever compiled a project consisting of both C and C++ parts, you'll surely have noticed that the directories full of C are whipped through at a much faster rate than those full of C++.

Would a Ruby script have been simpler?
It's rare for me to use anything other than Ruby these days if I need to write a program that takes an input file of some sort and produces an output file containing some other representation of the same information. Here, my hands were tied by the fact that I needed to use the AddressBook framework.

Or were they? There is actually a way for Ruby to have full access to native OS X APIs: RubyCocoa. I downloaded it, patched it to work on 10.3 (it doesn't work out of the box), patched it to include the AddressBook framework (trivial, but again, it doesn't work out of the box), and wrote a Ruby script equivalent to my little Objective C++ program. To my surprise, they turned out roughly the same length, with neither obviously much clearer than the other. If I had to pick a winner, I'd go with the Objective C++ program because it will run on anybody's Mac.

On reflection, I guess I'm so used to regular expressions being fundamental to this kind of translation task that I tacitly assumed not having them in Objective C++ (without third-party frameworks) would be a handicap. My gut feeling for what would be better/easier/shorter written as a script is in need of some revision.

I got a useful little program out of this, and I learned a bit about Objective C++, even if some of what I learned was disappointing.

What I really want to do now is display the weather forecast in my calendar, but I've not worked out how to do that. Anyone know how to do something along the lines of the GNOME "weather calendar" bounty?

How about having Mail understand MS Outlook meeting requests, and forwarding them to iCal?

If only Apple would give us the source...