August 16, 2007

Dates and times, and specification examples

Scheduling is a big part of our kickass product for nursing homes (coming soon!). Generally there are:

  • appointments (Mrs. Slugworth has a beauty shop appointment on Tuesday at 4:30),
  • recurring appointments (Mr. Dahl has a dialysis treatment every other Wednesday at 1:30),
  • many types of scheduled care (record weight every Sunday at 3:00 and the last Wednesday of every month at 3:00; do not give fluids for eight hours starting at 2 AM on August 13th; offer fluids every two hours between 6 AM and 9 PM from August 2 to September 15; etc.)

One of my fundamendal tenets of software development is that anything dealing with dates and times sucks hard. You have to deal with weird measurements (leap years, inconsistent month lengths), timezones, synchronization, agreement on units of measurement, and it’s one of the relatively few areas of ubiquitous low level computing that can be influenced by human politics. Fortunately many other people much smarter than me have come to the same conclusion and have developed libraries and specifications to deal with the suck.

The infantry library for us is Joda Time, which is in my top five open source Java libraries ever. Partially because what it replaces – the datetime handling in the JDK – is so awful. But it’s also because it’s designed by people who have actually used dates and times in the real world, and because it encourages good practices by using immutable objects as the default and making everything threadsafe.

But that only deals with dates and times, not recurrences. The 800-pound gorilla in the recurrence space is RFC 2445, “Internet Calendaring and Scheduling Core Object Specification” or “iCalendar”. iCalendar deals with every aspect of scheduling I can think of, and one of the trickiest is recurring schedules. The formal definition for the ‘RRULE’ (section 4.3.10) is a page and a half, and that doesn’t even scratch the surface of what it actually means. The description of each field fills up another two pages: more useful, but still a little abstract for practical use.

For me, the best part comes later, in section 4.8.5.4. It includes six pages of explicit examples, like these three:

Every 10 days, 5 occurrences:
  DTSTART;TZID=US-Eastern:19970902T090000
  RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
   
  ==> (1997 9:00 AM EDT)September 2,12,22;October 2,12
 
The first Saturday that follows the first Sunday of the month,
 forever:
 
  DTSTART;TZID=US-Eastern:19970913T090000
  RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
 
  ==> (1997 9:00 AM EDT)September 13;October 11
      (1997 9:00 AM EST)November 8;December 13
      (1998 9:00 AM EST)January 10;February 7;March 7
      (1998 9:00 AM EDT)April 11;May 9;June 13...
  ...
  
Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
 
  DTSTART;TZID=US-Eastern:19970902T090000
  RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z
 
  ==> (September 2, 1997 EDT)09:00,12:00,15:00

When writing any type of documentation it’s easy to assume your reader consumes what you’ve written as carefully as you’ve produced it – from front to back, paying attention to your highlights and thinking deeply about your assumptions and goals. But IME few people have the inclination or luxury of reading that way – it’s, “How can I do job X?” Examples are the best way to do this; if your library is good enough, they’ll get to the other (still important) parts later.

(BTW, the library we’re using for recurrences is Google’s RFC 2445 implementation. It’s okay (it has Joda Time integration!), but IMO needs some usability improvements. When I get a few minutes to breathe this fall I hope to try and contribute…)

Next: Dirges for Java
Previous: Hooray for standard formats!