My inclination would be to use absolute timing instead of relative (elapsed) timing. The reason is twofold:
1. Absolute timing is dead easy to code and seems easier to manage as you introduce new and arbitrary events that might fall between preexisting events that you've created. Assuming you're not looking for ms accuracy, polling overhead won't be a big deal.
2. With elapsed time, you run the risk of progressively falling behind schedule if events take longer to execute than you have anticipated or coded for.
This is one of those "I'm sure it's been coded many times before" applications, but it seemed like fun, so I coded it up using a standard state machine. Mine uses a schedule-info array to define events and assumes that the elements of the array are ordered chronologically.
Hope it helps,
John