mo@uunet.UU.NET (Mike O'Dell) (01/13/88)
I just had a long conversation with Dave Mills about time ticking and he is now of the opinion that jiggering the "real clock", i.e., the gicky the ticks away at some fairly regular rate is wrong. The correct solution for synchronizing is to maintain an offset between the "local real clock" and "global absolute time". Note that for high precision, this requires maintaining not only the last known offset, but the 1st and 2nd derivatives so the drift can be interpolated (to quite astonishing accuracies, it turns out). In this scenario then, the offset reflects any leaping, not the basal clock. The "local apparent time" is formed by adding the last known offset plus the interpolated drift term to the current value of the real clock. (Note that the interpolated value is a function of the difference between the local real clock at the last offset synchronization and its current value. This makes the calculations a bit tricky if you want high precision.) Therefore, the right place, I would argue, to put leaping is in ctime(). I prefer to think of ctime() as a mapping between external absolute time and the system's internal relative representation. If you take this view, then it is clear that is where it goes. Besides, I dunno how to set the clock WITHOUT leapseconds! If you listen to WWV on a cheap plastic short-wave radio to set the time, you get leap seconds! So if you ain't supposed to put them in, you gotta manually subtract them! Oh yes, I just realized it - the problem stems from using an epoc-relative representation. Absolute representations don't have the problem, or at least push them so far into the past as to not matter. For example, 0400 UTC December 9, 1987 doesn't suffer the bias - it's built-in!! -Mike
dmr@alice.UUCP (01/14/88)
It seems to me that the POSIX wording ("ignoring leap seconds") is essentially correct, though the specs could be made more precise. One postulate (not related to time as such) is that it would be rather impolite to make everyone change their ctime function to get reasonable conformance. A second postulate is that the successive numbers returned by time(2) should increase by 1 each second, and not skip or pause. A third is that time errors in the distant past are considerably less important than ones near the present. Ctime operates by dividing the value of time(2) by 86400 to get days, converting this to YY/MM/DD, and converting the remainder to HH:MM:SS. Because of leap seconds, there are not always 86400 sec/day; thus ctime ignores leap seconds (as specified by POSIX). But the time "now" is correct. So where did the leap seconds go? One way to think of the situation is that the epoch (and in fact all times before the leap second) moves whenever we have a leap second. Practically always, all this means is that doing ctime() on a old date will be wrong by some number of seconds. Most people don't care; those who do, can install a nicer ctime like the posted one. It is true that if you execute "while sleep(1); do date; done" across a leap second, you will not ever see the time "23:59:60" as you should; and moreover, your ctime will be off by 1 sec until you do something (reboot, jam the clock, skew your clock by listening to WWV, whatever). I claim that for the vast majority of people, this witching period (where an "old date" is in fact recent) is of little consequence; if it is, they can fix their ctime to know about the leap second. What would be wrong is to change the meaning of time(2) as interpreted now, for any value of now. For example, we run a WWVB synchronized time server that puts out Unix Standard Time on a network, and probably some hundreds of machines use it directly or indirectly. We would consider it unfriendly to jump the number it puts out, and force everyone to change their simplistic ctime routines that work well almost always. Dennis Ritchie
trt@rti.UUCP (Thomas Truscott) (01/16/88)
Dozens of UN*X people have known of the leap second bug in ctime (and in the inverse routines) for well over a decade. Whoever wrote ctime (was it dmr?!) did a great job, but it has suffered bit rot as the years have gone by. It is a shame that people have been too lazy to fix the leap second bug. Ctime has worse problems that have not been fixed either. Ignoring these problems will just delay the inevitable, and documenting them as a standard will just make things worse. It is NOT too late to fix these problems, nor is it too late simply to postpone the issue for future consideration. In article <7622@alice.UUCP>, dmr@alice.UUCP writes: > One postulate (not related to time as such) is that it would be rather > impolite to make everyone change their ctime function to get reasonable > conformance. ... > A third is that time errors in the distant past are considerably less > important than ones near the present. Fine, let's redefine EPOCH to be 14 seconds before 0000 Jan 1 1970 GMT. That is a lot cleaner than "ignoring leap seconds." Of course if ctime (and its inverse routines) persist in their ignorance of leap seconds (as the new standard demands) then we will have periodic glitches in time. Do people want this from here to eternity? And then there are the ctime problems with daylight savings time. There are areas in the US today where ctime gives the wrong answer. Is that reasonable conformance? And there will be big problems when the US Congress (or a state legislature) changes the rules about daylight savings time. I consider it "impolite" of ctime to give me wrong answers. The number one flaw in ctime is that there is no mechanism by which it (and its inverse routines) can cope with future, unpredictable, changes in the time reporting system. Once this problem is addressed, the problems of daylight savings time, etc. *and leap seconds* will magically disappear. May the root have mercy on my impertinence, Tom Truscott
guy@gorodish.Sun.COM (Guy Harris) (01/16/88)
> So where did the leap seconds go? One way to think of the situation is > that the epoch (and in fact all times before the leap second) moves > whenever we have a leap second. Unfortunately, this is inconsistent with the wording in POSIX Draft 12, wherein it states that "The Epoch refers to the time at 0 hours, 0 minutes, 0 seconds, Coordinated Universal Time on January 1, 1970." There is only one such instant; it can't move. If the POSIX spec *meant* to say that, when converting "time_t" to "struct tm", the conversion code should act *as if* leap seconds weren't counted in the result of "time()" (even though they are, unless you stop your clock during leap seconds), it should say so - which means this should be described in Chapter 8, the section where additional information about C language library routines is presented. I still think that all efforts to work hard at interpreting the POSIX document in an unusual manner so as to permit existing systems to conform are doomed to failure; the spec is rather unambiguous, in that 1) it refers to a particular instant of time that cannot move, and 2) it specifically says that leap seconds are not counted. The only possible interpretation of this that I can see is that, if a total of 569,022,442 seconds have elapsed since the Epoch (which was true at one particular instant a few days ago), as defined by some standard outside of POSIX (e.g., a counter driven by a cesium-beam clock and set to zero at that instant by the BIH or whoever standardizes these things), "time()" must return 569,022,428, as it is not supposed to count leap seconds. Ultimately, the leap seconds problem can be finessed if the POSIX spec is also fixed so as not to mandate that systems *do* sync up with e.g. WWV; the wording in the POSIX spec would render my system non-conforming, since 1) my machine's clock drifts and 2) I don't call WWV every morning to set the time, nor do I have it attached to a WWV clock. Were the standard to permit a system to make a reasonable effort to sync up with UTC, but allow it to be off by a couple of seconds or so (or perhaps even a couple of minutes), a system that doesn't take leap seconds into account would have a "ctime" that gave times that were off by a couple of seconds, but that wouldn't cause it not to conform. If the user cares about this, they can buy a system that has a "ctime" that undestands leap seconds (and also sync it up with a WWV radio or somesuch); if they don't care about this, they're not obliged to buy such a system. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
rbutterworth@watmath.waterloo.edu (Ray Butterworth) (01/18/88)
In article <1980@rti.UUCP>, trt@rti.UUCP (Thomas Truscott) writes: > And then there are the ctime problems with daylight savings time. > There are areas in the US today where ctime gives the wrong answer. > Is that reasonable conformance? > And there will be big problems when the US Congress (or a state legislature) > changes the rules about daylight savings time. > I consider it "impolite" of ctime to give me wrong answers. > > The number one flaw in ctime is that there is no mechanism > by which it (and its inverse routines) can cope with future, > unpredictable, changes in the time reporting system. > Once this problem is addressed, the problems of daylight savings time, > etc. *and leap seconds* will magically disappear. One of the main problems is that time_t tries to be too many things for too many people and never quite manages to do everything that is expected of it. time_t works fairly well as a time stamp for file changes and such system related things. It is when it comes to a human interface that its deficiencies become more apparent. A library (portable, not-necessarily-unix, etc.) that I've been working on provides a complementary solution (definitely not a replacement). The idea is that when a human enters a time he is refering to the time on his watch or on the wall clock. If he says "2 days from today", or "6 months from now", he would expect the date to change but not the clock. It shouldn't matter that 2 days from now is actually 1 second earlier because of a leap-second, or that 6 months from now is actually 1 hour earlier because of daylight saving time, or 4 hours later because he's moved to a different time zone. Similarly, asking for the difference in time between "10:15 Aug 17" and "10:15 Jan 12" should give an answer that is an exact number of days. i.e. time is kept track of ignoring time-zones, leap-seconds, DST, or any other complications that might arise in the future (short of a major change to the calendar). I haven't yet needed it, but it wouldn't be difficult to add another function that could give the real difference in time between two of these times taking into account leap-seconds, DST, time-zones, and currently known acts of government. I realize that this idea is hardly original, and is in fact a giant step backwards. But for many applications it works much better than the more precise (and therefore more often incorrect) values given by the size_t functionality.
guy@gorodish.Sun.COM (Guy Harris) (01/19/88)
> time_t works fairly well as a time stamp for file changes and such > system related things. It is when it comes to a human interface > that its deficiencies become more apparent. It was never intended to be used as something for humans to deal with directly. That's what "struct tm"s are for. If you want to know the number of seconds that will elapse between two events (*counting* leap seconds, of course; we all get one second older during leap seconds just as we do during regular seconds), you should be able to get the time stamps of those two events and subtract them. (This is one reason why the times returned by "time()" should NOT exclude leap seconds.) If you want to know how much time separates the two events, with the proviso that e.g. 11:30 tomorrow is to be considered precisely one day after 11:30 today, daylight savings time, leap seconds, etc. nonwithstanding, you get the two events dates/times as "struct tm"s and subtract them component by component. Similarly, if you want the date/time for "two days from now", you get "now" as a "struct tm", add two to the current day-of-week value and do the appropriate "carry propagation" (carefully, taking into account time zone changes, etc.) Unfortunately, while UNIX systems have - and ANSI C implementations, barring surprising changes in the standard, will have - a routine to convert from "time_t" values to "struct tm" values, most UNIX systems have no routine to go the other way. The current ANSI C draft does include a routine that goes from a "struct tm" to a "time_t"; the spec says that routine has to do the aforementioned carry propagation. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com