The DOS Think way of keeping time is fundamentally broken.

The DOS Think way of keeping time is how time and timezones are managed in MS/PC/DR-DOS: The hardware real-time clock runs in local time, with daylight savings time adjustments, for one system-wide timezone, applied on the fly by the operating system (or manually twice a year by the system administrator). It is fundamentally and irredemably flawed. Nonetheless, people still use it even now. It's still the thinking as employed by Windows NT, for example.

It is, however (which surprises some people), not the way that 32-bit OS/2 was actually designed to keep time. Nor is it, of course, how Unix and Linux (when the latter is properly configured, at any rate) keep time.

The basic problems are twofold.

The first basic problem: There's no universally recognized flag for recording the current standard/daylight savings time state.

The first basic problem is a simple one: There's no flag in an MC146818 real-time clock chip (and thus in its emulators in modern chipsets) that says "This clock has had daylight savings time corrections applied.". (An equivalent flag would be "Daylight savings time is/is not currently in effect.")

The reason why this is a basic problem is that in order to have a DOS Think timekeeping system work reliably (where this is defined as being at least as reliably as the Unix-Linux-OS/2 way of keeping time is) with respect to daylight savings changes, a persistent flag is required, in a place that every DOS Think operating system agrees upon, that is updated at DST changover points even when the operating system is not running.

If there is no flag, or if different operating systems disagree as to where the flag is so that they each use different flags, or if the flag doesn't change when a DST transition occurs when no DOS Think operating system is running, the system becomes a mess.

Examples of messes

Examples of how the system becomes a mess abound. They've been reported many times, by many people, since the 1980s. They are a perennial staple of the RISKS Forum.

What happens when there is no flag at all is exemplified by the behaviour of DOS-Windows 95, as reported by Dale K. Brearcliffe in 1997 and again by R.A. Downes in 1999. If there's no flag saved anywhere to say what the current DST state of the RTC is, when it comes to adjusting from daylight savings time to standard time, automatic adjustment enters the world of 12:01, where the same hour repeats endlessly. The adjustment procedure has no way of knowing whether the adjustment has already been done, no way to know that the RTC is already in standard time, and so proceeds to set the clock back one hour, hour after hour.

Having a flag is no better if there's no agreement amongst different operating systems where it is. Windows NT stores its flag in the registry, in the ActiveTimeBias value of the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation key. But, of course, multiple copies of Windows NT will each have their own registries, all with their own separate copies of this flag. So bootstrapping multiple operating systems will result in the same adjustment being applied multiple times. (This is made worse if the different operating systems are configured to use different switchover rulesets, or if one does things like backing up and restoring that part of the registry.)

Multiple instances of the same operating system are but one variant of this. DOS+Windows 9x stored a similar flag in its registry, too. The problem of DOS+Windows 9x and Windows NT 2000 not sharing a single machine-wide flag, but each instead using their own registries, was reported on by Bruce E. Wampler in 1996 and again by Paul Schrieber in 2002 (and yet again by Colin Andrew Percival in 2002). Again, the behaviour is that automatic changes to the hardware RTC are applied cumulatively by the individual operating systems, resulting in a clock that is incorrectly several hours ahead or behind where it should be.

Even the PC99 et al. specifications lack a standard flag.

One might think to allocate one of the unused non-volatile registers that MC146818 provides, and simply use it for such a flag. Storing the flag on the chip itself, in areas that the chip itself provides for non-volatile storage, seems like an obvious answer. Unfortunately, there's a good reason that Windows NT didn't take this fairly obvious approach. As those who have read the CMOS.LST document in Ralf Brown's Interrupt List will already know, there's no standardization of NVRAM register contents (each firmware manufacturer having its own ideas about what is stored in which NVRAM register) and most NVRAM registers already have between two and six different meanings (varying by firmware manufacturer).

Even the PC98, PC99, and later specifications didn't standardize a flag location. There's simply not the room for it.

The second basic problem: The hardware clock yields values that are ambiguous or outright impossible for local time.

The second basic problem is another simple one: A hardware real-time clock in normal operation produces time values, twice a year, that are either ambiguous or impossible values for local time.

For example: If DST changes occur at 01:00:00 standard time then the local time 01:30:00 doesn't exist on the day that local time changes from standard to daylight savings time. Yet a hardware RTC will yield such a time in the normal course of operation. Similarly, the local time 01:30:00 exists twice on the day that local time changes from daylight savings to standard time. It's impossible to know (because of the first basic problem) which time is being represented by a hardware RTC when it reads 01:30:00 on that day.

There is no way to program an MC146818 RTC to apply (an arbitrary country's) DST changes itself. (The MC146818 had a circuit to apply DST changes. It only applied the United States DST rules, and only worked correctly for a mere three years before the law changed. It's been useless for this purpose for more than a quarter of a century.) In the normal course of operation a hardware RTC yields a non-repeating, uniformly increasing, value. Local time simply doesn't work this way, and it's impossible to correctly, and unambiguously, map values from the hardware into a consistent local time value.

UTC does work this way, if we ignore leap seconds. (TAI doesn't have leap seconds and definitely works this way. But that's another discussion.) As reported by Len Spyker in 2007 a hardware RTC simply never yields unambiguous or impossible values if it is taken to be running in UTC (or, better, TAI) rather than local time. As Spyker also noted, bootstrapping a DOS Think operating system during the periods where the hardware RTC yields values that are ambiguous or impossible local times will yield behaviour that varies according to how one's particular operating system has chosen to guess at the actual local time in such circumstances. There are various guessing strategies possible, which yield differing results.

DOS Thinking on EFI

Basic problem #1 no longer exists on machines with EFI firmwares. The EFI Specification defines GetTime() and SetTime() functions, in its "Run-Time Services" API, for operating systems to call. Those services employ a data structure that has a TimeZone field and a Daylight field. The latter field has two bitflags: one (EFI_TIME_ADJUST_DAYLIGHT) to say whether the system is configured to have DST changes applied to the hardware RTC, and a second (EFI_TIME_IS_DAYLIGHT) to say whether daylight savings time is currently being applied.

EFI doesn't specify the physical storage location of the flags, and they are not necessarily stored anywhere near the MC146818 (or equivalent) chip. In fact, they are usually going to be stored using the same non-volatile storage mechanism that is used for storing EFI variables — which is usually the NVRAM chip that is used for holding the firmware itself. Different manufacturer's EFI firmwares are free to store the timezone and daylight flags wherever they like. That isn't important. The important factor is that on any single machine all operating systems are going to be accessing the flags through the same APIs, GetTime() and SetTime(), so to all operating systems the flags are centralized and common. Flags and timezone changes made by one operating system will be visible to all others (that call the proper firmware API functions).

However, EFI doesn't necessarily eliminate basic problem #2, because that's a hardware problem. The solution to the second problem is to never try to run the hardware RTC in anything other than TAI (or at least UTC) so that there's no possibility of the hardware register state being ambiguous or impossible. Of course, an EFI firmware system can do this, since operating systems are not supposed to be accessing the clock registers directly but instead using the EFI API functions, and so the firmware can perform a completely invisible translation between local time, as (potentially) spoken by operating systems calling the GetTime() and SetTime() functions, and TAI/UTC, as actually programmed into the hardware RTC registers. The requisite information is all there in the fields of the EFI_TIME data structure. It's not specified that an EFI firmware should do this, though, and it is possible that poor quality EFI firmwares do not.


© Copyright 2009,2012 Jonathan de Boyne Pollard. "Moral" rights asserted.
Permission is hereby granted to copy and to distribute this web page in its original, unmodified form as long as its last modification datestamp is preserved.