This is not an article about current affairs
Over the last few weeks, I had several interesting run-ins with time, specifically how time is represented and processed by computers. Deep down it’s really all about a clash of human culture and history with physical reality.
At one extreme, there is local time, with noon exactly when the Sun is highest in the sky. Different depending on where you are, and exactly how humans worked with time throughout most of recorded history. That approach works very well as long as people and information can’t move much faster than about the speed of a horse. The 19th century introduced train travel and telegraph. If one sat on a train and started going eastwards or westwards, it didn’t take long for a pocket watch to get increasingly out of sync with local time. To solve that problem, and make it possible to maintain and publish usable schedules, time zones were introduced.
To solve a different problem, or perhaps cause more problems, the 20th century introduced daylight savings time. To cause maximum pain to computer scientists, daylight saving is not observed universally and is not constant. A real winner in this category is probably Egypt’s 2016 cancellation of daylight saving time three days before it was due to begin.
To communicate over longer distances, computers are forced to agree on a common definition of time. That is the other extreme: UTC, or Universal Coordinated Time, which conveniently doesn’t know any time zones or daylight saving and is the same everywhere on Earth (modulo relativity effects).
Sadly, computer users only care about local time, which means computers have to convert between local time and UTC all the time. That is merely complicated when that time is “now”, hideously difficult when the time is in the past, and impossible when the time is in the future.
A Bit of History
Computers are old enough that when they started out, only local time was used. The Motorola MC146818 real-time clock (RTC) chip used in the IBM PC/AT (1984) perhaps represents the pinnacle of the old thinking. The chip has built-in calendar and automatically advances minutes, hours, days, months, and years as it counts seconds. Not only that, it can automatically (optionally) adjust for daylight saving time, starting on the last Sunday in April and ending on the last Sunday in October.
The Motorola RTC was designed around 1983, when the Uniform Time Act of 1966 had been in effect for more than 15 years. It’s too bad that in 1986, the daylight saving functionality of the chip was already destroyed by moving the daylight saving time beginning to the first Sunday in April.
At any rate, an IBM PC/AT running DOS used strictly local time. All dates and times were recorded in local time; moreover, there was no system-provided way to set the local time zone. As a consequence, the operating system has no chance to determine UTC.
In a completely unrelated development, wide area networking was becoming more and more common. With the arrival of technologies like e-mail and usenet, local time was no longer adequate. How do you chronologically sort a set of e-mails that were sent around the same time but from different time zones, or with different daylight saving time? You don’t—not without knowing the corresponding time zones (and therefore, UTC offsets).
Microsoft’s Bad Influence
In the world of PCs, the initial PC/AT architecture led to poor design choices which to some extent persist to this day. As mentioned above, the PC/AT RTC was meant to be run in local time. The problem is that PC-compatible firmware provides no way to record or indicate a) the local time zone, and b) daylight saving time.
That leads to minor but completely unsolvable problems related to daylight savings. As mentioned above, the RTC cannot handle actual daylight saving time (DST) changes according to current rules, therefore the clock must be run with DST off. The unavoidable consequence is that when the system is powered up in the DST transition window (typically one hour in Spring and one in the Fall), the OS simply cannot determine what time it is because it has no way to tell if DST has been already applied to the RTC or not.
That is in theory not an unsolvable problem, after all the RTC’s non-volatile RAM could easily store this information—if all firmware vendors could agree on how. But they never did, because it wasn’t their problem, it was the OS vendors’ problem.
The issue is exacerbated if multiple operating systems are installed on the machine, each correcting for DST, as is the default with Windows. Each OS keeps its own DST correction flag, and therefore each will want to adjust the clock, making the problem worse rather than better.
The obvious solution is to not run the RTC in local time but use UTC instead. That is what most Unix-style operating systems have been doing for many years. That is also something that Windows NT has been designed to do from the beginning, but due to implementation bugs and lack of user interface, RTC in UTC has never been widely used with Windows.
The original behavior was justified in the early 1990s when multi-booting various operating systems was common and most of them only supported the RTC to be run in local time. It was counter-productive in the 2000s when a PC in almost all cases only had some Windows NT derivative on it, or could multi-boot to several NT versions and/or Linux.
There is no technical reason why the PC’s RTC can’t be run in UTC; it can. The only problem is Microsoft’s inertia. This might be one one of the few areas where EFI actually helps, because EFI does have a concept of time zones and UTC offsets.
There is also no technical reason why the RTC couldn’t be run in the local time zone but always without DST adjustments, and let software apply DST or not. But because existing OS software expects the RTC to be in local time including DST, that was never done.
It is apparent that the PC/AT and compatibles are to some extent victims of poor timing. The PC/AT was designed with the idea that the DST is predictable, and the RTC could take care of it. That was not a crazy thought in 1984 (at least considering the American market). But a few years later, poof, that assumption went out of the window—and it was too late to correct the initial design.
What Time is it Again?
The historic computer behavior leads to annoyances that are known to computer archivists. An old FAT-formatted floppy or hard disk, but likely also an old ZIP or similar archive, contains timestamps in local time. With absolutely no information as to in which time zone that local time was.
What happens when such file is copied onto a modern file system which does keep timestamps in UTC? Why of course, the OS just quietly makes something up. Given the utter lack of information the OS has, the alternative would be to ask the user what the time zone was when copying such files. Except the user almost certainly does not know either, so making something up is, on balance, really the least bad solution.
Which does not make it any less annoying. The conversion happens invisibly and suddenly one ends up with multiple copies of the same file with different timestamps, and then which one is the right one?
This is especially problematic in the fairly common case where the timestamps were synthetic and the hour:minute portion indicated the version number; for example, MS-DOS 6.22 files are timestamped 05-31-94 6:22a. That only makes sense if the time is shown the same everywhere, even if it is technically wrong.
A Rare Bug
And now for something slightly different, a bug that I recently had an opportunity to investigate. Out of the blue, software running on customers’ systems suddenly came up with the wrong date, after showing no issues for at least six months.
After much head scratching, it turned out that a routine determining the local time offset from UTC failed if it was run on the 2nd of a month, and moreover if it was run in a window between midnight and the local offset from UTC (e.g. between midnight and 2am in summer in most of Europe, but between midnight and 9am in Japan). That window does not exist in the timezones “behind” UTC, and in Europe and most of Asia it’s well outside of working hours.
The failure mode was determining the direction of UTC offset incorrectly in the problem window, when the local and UTC dates were different. As a result, the calculated date would end up being off by two days, although the time of the day was correct.
The bug had been in place for slightly more than ten years before it was discovered.
A Rarer Bug
While working on the above problem, I tested the behavior of various C run-time library routines. Among others I used the Open Watcom compiler. I noticed that the localtime() results did not match the data produced by the OS X system compiler when the local time was just after the switch from DST to standard time (that is, within an one-hour window once a year).
After a bit of debugging, it turned out that the problem was surprisingly trivial. The Watcom C run-time works with DST start and end times specified in terms of standard time. When parsing the TZ variable, the run-time took that into account and adjusted the DST end time (which the TZ variable specifies in terms of local time, i.e. with DST in effect).
When there was no TZ variable, the Win32 flavor of the C library run-time took the information from the GetTimeZoneInformation API. Which also specifies the DST end in terms of local time. And in that case, the time wasn’t adjusted, which caused the run-time to get it wrong and produce incorrect results in the narrow window around the end of DST.
The bug has been in the Watcom C run-time library for quite some time, unnoticed or at least unreported. It has now been fixed by applying the DST-to-standard time adjustment. It was likely to fly under the radar because the results were not wildly off and only affected (typically) one very early morning hour within a year.
I am almost certain that the MSVC 7.1 run-time has a similar but different bug related to DST changes, but I have not investigated it in detail.
Even with no bugs, DST causes undue stress to computer scientists. The problem is that it’s not constant—just because year X has given DST start and end times doesn’t mean year Y has the same start or end, or is applied at all.
To handle accurate worldwide local time to UTC conversion of past dates, it is possible to keep a database of all historical DST data for all locales in the world. That can get out of hand quickly. Fortunately this doesn’t matter too much, especially when going further than a few years into the past.
Handling accurate worldwide local time to UTC conversion for future dates is, on the other hand, simply impossible. There is no way to predict future DST and time zone changes. Again, fortunately 100% precise conversion usually does not matter, especially going further into the future.
Moral of the Story
Time is hard. Because humans make it hard. Getting it 100% correct in software is quite difficult, if not impossible.