New Message: Re: Dates before '91

webmaster at userland.com webmaster at userland.com
Wed Jun 21 19:46:59 CDT 2006


A new message was posted:

Address: http://frontier.userland.com/discuss/msgReader$14448

By: Matt Deatherage (frontier at gcsf.com)

date.get ("12/31/90", @day, @month, @year, @hour, @minute, @second); year

returns: 1911

You also get "1911" if you try the date "12/31/2090", pretty much confirming Lawrence's hypothesis. Frontier is assuming that the year "90" is in this century, not last century.

Now that Frontier is open source, can we find the answer to this in less than 10 minutes of Xcode searching? As it turns out, we can: timedate.c, line 914:

 if (year < 100) { /*use script manager's StringToDate heuristic -- pg 188 in ß docs*/

 long thisyear, lcentury;

 GetTime (&date);

 thisyear = date.year % 100;

 lcentury = date.year - thisyear;

 if ((thisyear = 90)) /*assume last century*/
 lcentury -= 100;
 else
 if ((thisyear = 90) && (year <= 10)) /*assume next century*/
 lcentury += 100;

 year += lcentury;
 }

"year" is the passed-in value of your date. So, we get the current date (21 Jun 2006), and then take the remainder of the year (2006) when divided by 100. "thisyear" becomes 6, and "lcentury" becomes 2000.

In the first test, thisyear is less than or equal to 10 (6 <= 10), and the year of your date is greater than or equal to 90 (90 = 90), so Frontier subtracts 100 from lcentury, making it 1900. It then adds that to the passed in value for your year, 90, and gets back 1990 for the year.

At least in theory. The source doesn't indicate that this code has been altered since Frontier 5.0a12, but I can verify that in the current Frontier 9.5 on Mac OS X 10.4.6, the application is indeed treating "90" dates as "2090" instead of "1990". This is a double bug, because "2090" is outside the range of the 32-bit Mac OS X unsigned long "secs" variable.

The heuristic is described here [1], and basically says that during the first decade of a century, two-digit dates in the 90s are treated as in the past 10-20 years, not 80-90 years in the future. Similarly, in the 90s, two-digit "00" to "10" years are assumed to be in the next decade, not 80-90 years in the past.

The only crapulent part is that I can't verify that Frontier is somehow treating your year as "2090" other than by trying "12/31/2090" and getting the same result you get for "12/31/90". Your date is seen by Frontier as "31 Dec 2090 12:00:00 AM". In theory, on Mac OS X, you subtract the end of the original Macintosh date duration from that and you get a difference of 50.899 years (0x5FBD4381 seconds). In theory, if Frontier passes "2090" as the year to the Mac OS, it should overflow as documented, and the date you get back should be (passed in date - 6 Feb 2040 06:28:15 AM) + (1 Jan 1904 12:00:00 AM).

In this case, you should be seeing "24 Nov 1954 05:31:45 PM". Instead, you're getting "28 Jul 1911 12:00:00 AM". I can't find any support in the source code for that happening, so I can't tell you exactly where the boundary is. If I pass in "2/6/2040 6:29 AM", just 45 seconds past the wrap-around spot, Frontier indeed returns "1 Jan 1904 12:00:44 AM". But I can't explain why passing in a two-digit year of "90" gives you a result in 1911 instead of 1954.

The good news is that if you use four-digit years on your own, you'll get the answers you want, provided 1904 <= year <= 2039. Process "year" in the same way that Frontier's attempting to do before you pass it to date.get and you'll be in control of the weirdness.

This concludes today's scheduled technical diversion.

[1] http://developer.apple.com/technotes/te/te_520.html

This is a Manila site... http://manila.userland.com/.




More information about the Manila-Server mailing list