Fun With Testing DateUtils.pas #7

Note: This is a “reprint” of content from my blog on Embarcadero.com when I was working there.  They’ve since shut down my blog and the content is gone.  I’m republishing it here.  See the main article for more information.

Okay, so after that last post, and after all the fixes that I did, things have settled down a little bit.  I thought I’d take advantage of this interlude to tell you some interesting things about TDateTime in Delphi, because along the way here, I have discovered a thing or two along that way that was surprising.

The first thing that you might be interested in is that the calendar used by the Delphi TDateTime has a specific name:  The Proleptic Gregorian Calendar.  Calendars, of course, have been notoriously inaccurate over the years, and even ours isn’t entirely accurate in that we have to have leap years every so often (and not as often as one might believe…). We even have these “leap seconds” every once and a while, though the notion of being able to measure things down that precisely is kind of weird.  Starting with the Romans – Julius Caesar, actually – the Western world used the Julian calendar.  And that worked pretty well, actually.  The Julian calendar worked pretty well – it has 365 days and a leap year every four years – but it wasn’t entirely accurate, and (as you can read in the Wikipedia entry) politics got involved, and the calendar got out of whack pretty easily and pretty often.

So anyway, as you may have noticed, some of the tests that I have written include some pretty big time increments – like 1000 years worth of seconds and things like that.  And I also wanted to makes sure that the incrementing routines worked across the epoch of December 30, 1899.  So I had to be able to do some pretty serious calculations.  I found a pretty good website to do those calculations called timeanddate.com.  This site has a bunch of calculators for measuring between dates and time and for calculating a date based on distance from another date.  So I used it to figure out what the date was if you decremented two hundred years worth of seconds (that’s 6,307,200,000   seconds for you math geeks….) from, say, Noon on June 30, 1945.  (It’s not exactly noon on  June 30, 1745 due to leap days.)  Well, I would calculate it, and then write the tests, but they would fail because my expected result was always eleven days different than the test result.  Eleven days – how weird, huh?

Well, here’s the deal.  Somewhere along the way, the really smart guys who figure out this kind of thing came up with a new calendar – the Gregorian calendar.  It’s different from the Julian calendar, and starting in the 16th century, the world gradually converted over to use the Gregorian Calendar instead of the Julian calendar (A good chunk of Europe started in 1582, and the last folks to make the switch were the Russians who didn’t change until 1918).  But to do that, you usually had to skip about 10 or 11 days.  Great Britain and all of its possessions (including the colonies that would become the United States) made the switch in 1752.  Therefore, in the English world, the day following September 2, 1752 was September 14, 1752.  There was no September 3 – 13, 1752.  Just didn’t exist.  Once I discovered that, it explained the missing eleven days.

But what does this mean for our trusty TDateTime?  For a minute there I was afraid that I was going to have to do all these special calculations to account for this unusual anomaly, but then I came to my senses and realized:  That can’t be right.  And I was right.  Instead, Delphi uses, as I mentioned above, the Proleptic Gregorian Calendar – that is, it assumes that the Gregorian calendar is in force all the way  back to January 1, 0001.  So for TDateTime, there is a September 4, 1752 (Noon on that day is the value: -53807.5) and every single date “like normal” all the way down to Year 1.  This makes sense, because trying to devise a calendaring system that keeps track of all the vagaries of the Julian calendar system would be basically impossible.  Instead, Delphi uses a system that “makes sense” for a computer.  A number of other languages and tools use the Proleptic Gregorian Calendar, including MySQL and PHP.

That was probably more than you wanted to know about TDateTime, but it’s all stuff that you have to know to write a complete test suite for DateUtils.pas. So far, that summarizes the issues that I’ve run across in testing the unit. I have a ways to go to have a complete test suite, but if I run across more issues, I’ll post on them.

The next post I do will be about a testing scheme that one of our developers, Alexander Ciobanu, devised to make writing tests for testing date functions a little easier.