[ Go to October 1997 Table of Contents ]|
Of Dates and Times
Last month, when referring to the Windows 95 version-checker Web page we're building, I explained how to determine file versions from an ActiveX object.
As usual, I wasn't done when I thought I was.
It turns out that the version resources in Windows 95 DLLs are inconsistent. In some cases, several versions of a file with different dates and different contents have the same internal version number. In other cases, version numbers are not kept in order. When that happens, it's important for a version-checking utility to be able to retrieve the file's size, date and time.
I thought adding that feature would be trivial. I was wrong.
GetFileTime fills a FILETIME structure-a 64-bit value representing the number of 100-nanosecond intervals since Jan. 1, 1601. (I'm sure that choice of starting date made sense to someone.) File time-stamps are given in Coordinated Universal Time (UTC), formerly called Greenwich Mean Time. So the first step in making sense of the file time is to convert the date to the local time zone and then to system time (which is always given in local time)
Win32 has functions for those steps, too: FileTimeToLocalFileTime and FileTimeToSystemTime. The latter fills a SYSTEMTIME structure, which represents the year, month, day of week, day, hour, minute, second and millisecond as individual WORD values. We now have the time zone corrected, the 1/1/1601 base date removed and all the individual values set, so we're ready to convert to the OLE date and time format. Right? Wrong.
This is the fun part: The OLE DATE type is an 8-byte floating-point number. The days are represented as whole-number increments starting with midnight on Dec. 30, 1899 as time zero (another starting date that must have made sense to someone, once). Hour values are expressed as the absolute value of the fractional part of the number. So Jan. 4, 1900 at noon is represented as 5.5.
I was absolutely sure there would be an OLE function to convert a SYSTEMTIME to a DATE. If there is one, though, it escaped my search. So I started to write such a function, and quickly found myself tearing my hair out over minutiae like leap years, days in months and that 1899 start date.
I thought about this a little more, searched for a Microsoft Foundation Class (MFC) method to do the job and found the COleDateTime class. COleDateTime uses the DATE representation internally, and includes constructors that convert from both FILETIME and SYSTEMTIME structures. However, I was explicitly not using MFC to create my component because of the large size of the MFC libraries.
So I dug up the source code for the COleDateTime class.
The COleDateTime constructor that converts from FILETIMEs relies on the constructor that converts from SYSTEMTIMEs, using the UTC/local time/system time-conversion sequence just as we've described it. I hacked and slashed the MFC source code a bit, and came up with the OleDateFromFT and OleDateFromTm functions (see sidebar "Set a Date")
I used these functions to write a four-line get function for a new FileTime property in my ActiveX object, and could retrieve file time stamps from VBScript almost as though
the capability were built into the language. Amazingly, the function worked correctly the first time. That's one big advantage of stealing previously tested code.
I'd like to send a big orchid (or perhaps a six-pack of beer and a pizza would be more appreciated) to whoever wrote the MFC COleDateTime class. I'd also like to send onions to the individual geniuses who created six incompatible date/time formats for Windows programmers: the OLE DATE format, the Windows SYSTEMTIME structure, the Windows FILETIME structure, the C time_t type, and the MS-DOS date and time formats.
At any rate, you'll find the full source code for the wmVer component, including the date conversion code discussed here, on my Web page at http://www.winmag.com/people/mheller/. And you'll find the version checking utility page at http://www.winmag.com/windows.
Microsoft's DHTML makes every element on a Web page accessible to scripts, no matter when the scripts run. In IE 3.0, you could generate HTML from scripts, but only "in-line" scripts, which run before HTML is sent to the browser. In IE 4.0, you can modify document and element styles, textual content, and HTML content even after the page has been displayed.
IE 4.0 also supports cascading style sheet (CSS) positioning. CSS lets you position every element relatively or absolutely on the page; you can also set each element's Z-order to control which element is on top when there is overlap. CSS positioning can be modified from scripts, so you can easily program sprite animation in DHTML. Finally, DHTML includes data binding, so it's no longer necessary to do all your database formatting on the Web server. DHTML supports data-aware "repeating" tables, which bind to server data sources but format the query results locally. That means the user can change the display order of a product catalog obtained from your Web page as easily as he can change the display order of a directory on his hard disk. No new database query is required. Now that's dynamic.
Senior contributing editor Martin Heller programs and writes about programming from Andover, Mass. Contact Martin at http://www.winmag.com/people/mheller/ or care of the Contact Lou care of the editor or the addresses on page 20.