Bad Timing

A cow-orker of mine once bragged about the DateTime class he’d written.  “It’s fantastic,” he said, “It handles dates from 10,000 BC to 10K AD, down to the millisecond. It does all the correct calendar conversions.  It knows about September, 1752. We don’t have to worry about our time API now.” He left the company a couple months later, and we shipped and started getting bugs from customers.

Most of the features he’d written were great on paper, but he’d never written effective unit tests. The code had a bottleneck that funneled everything through Unix time functions. Nothing prior to 1970 worked, nor anything past the Day of Armageddon in 2038. There was code to handle leap years, but it failed every 100 years.

I rolled up my sleeves and got into it. It was surprisingly hard to get it right. I spent about two weeks writing unit tests and making the thing work as advertised. Our start-up had a really neat smart messaging protocol with date/time as a basic type — we figured that since so many of our customers were getting it wrong, that we’d get it right and leverage that as a feature.

Something about “Those whom the Gods destroy they first make proud,” right. This is a class of problem that everyone knows is trivial. “Of course I know how to do this,” you probably think to yourself, “This is trivial, I can just code this thing up and have an early lunch.” Trivial is the most dangerous word in all of computerdom, it’s a misprounciation of “Evil”. Your blood should run cold if you hear it spoken out loud, because the Gods will be listening carefully and taking notes on how to screw you if they ever hear you say it.

When you deal with time, you have a number of choices.

  • What is the range of times you handle? Computer-era scale? Human (historical) scale? Geologic scale? Ridiculous death of the universe ranges, when protons have decayed, all galaxy-sized black holes have utterly evaporated and even Twinkies have gone a little stale?
  • What resolution do you need? Particle accelerators probably need jillionths of femtoseconds, for instance. Computer-scale times are probably on the order of hundreds of nanoseconds. Human-perceptible and most real-time processing can be done in milliseconds. Geologists don’t give a shit about a stretch of time less than a hundred thousand years.
  • What about daylight savings time? Time zones? Leap seconds? All the people who get this stuff wrong in the real world?
  • Do you need the ability to compare times? (This becomes an issue when you deal with some other time formats, for instance OLE uses floating point numbers, days since some epoch, and fractions of a day, and so representing 10AM exactly is impossible).

That’s just time; we’re not even getting into “date” issues like calendars, or holidays. Holidays are serial nightmares on roller skates.

I believe that most programmers (including this one) do not really understand time. It gets worse, though, when you have to deal with a hardware clock that was designed by a hardware engineer who not only did not understand time, but also failed to devise a way to reliably extract it from the circuit he designed.

“You set the Freeze register and wait, then read the value.”

“How long do I wait?”

“Um . . . about, well, a while.”

“How long is a while, given that this is the hardware that’s supposed to be telling me how much time is passing?”

“I guess you can just delay or something.”

So one of us is going to Hell because we have to turn off interrupts and spin for half an eternity, just to find out what time it isn’t any more. That tick you were interested in? Sorry, it happened while we were busy waiting for some moron of a flip-flop to make up its mind. See you last year.

Recommended reading: Calendrical Calculations. This is a really great treatment of time and calendars, and if you are writing any code in this area you should definitely read the first few chapters and then crawl under a desk and quiver, wondering how anybody gets this stuff right, ever.

Oh, and personal to you-know-who-you-are: I hope you are writing some bloody unit tests now. Right? Okay?