
From: Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> Resent-From: tz@elsie.nci.nih.gov The only doubts that I have about xtime is that I think it is with 96 bits a bit too long. I would feel slightly better with 64 bits. Yes, yes! This is the Right Way to Go. And we can do it, while still satisfying your other concerns. It would also completely mess up the elegance of my API in that suddenly strfxtime and xtime_make/breakup would have to know from what type of clock this timestamp came. strfxtime and the other primitives currently return garbage unless you pass them a TIME_UTC timestamp. I suppose one could argue that they return well-defined garbage; but this well-defined garbage is useless for practical applications. This is a defect in the current proposal, and I plan to propose a fix soon. But no matter how it's fixed, it's inevitable that either (A) time-zone-related primitives will have to know the timestamp's clock type, or (B) such primitives will be useful only on TIME_UTC timestamps. (A) is better than (B), particularly if we adopt solutions (2) and (3) mentioned below.
So I suggest that we give the programmer a way to access to the entire leap second table known to the implementation.
My API does this in form of tz_jump. Yes, but I see that I wasn't clear. Let me try to explain things better. I see three related problems with struct xtime in this area. 1. The struct xtime spec makes it difficult for applications to detect bogus or unknown leap seconds. Suppose an application constructs a leap second timestamp (i.e. a struct xtime value with 1000000000<=nsec<2000000000), and passes this timestamp to an xtime primitive that expects a TIME_UTC timestamp. Then the behavior is undefined unless the timestamp is not bogus (i.e. it is within a true inserted leap second) _and_ the timestamp is known (i.e. the implementation knows about the leap second). (The current spec doesn't say all this explicitly, but it certainly implies it.) Therefore, when importing a textual leap-second timestamp from the outside world, a struct xtime application can't blindly apply xtime_make and use the resulting value, as xtime_make might generate a bogus or unknown leap-second timestamp, which will cause problems when given to other primitives. So the application needs a way to find out whether a purported leap second is a known leap second. It can't pass the purported leap second directly to tz_jump, because if it's a bogus leap second tz_jump has undefined behavior. I can think of hacky workarounds to this problem, but this is getting way too complicated; there ought to be a simpler way to attack this problem. One way to fix this particular problem would be to change the spec so that every primitive reports an error when given an bogus or unknown leap second. This is an improvement, but it's not enough to address the other problems mentioned below; and solving the other problems will solve this problem. 2. The struct xtime spec is an awkward interface to implementations based on TAI that do not have full leap second tables. Suppose implementation X internally uses a clock with TAI seconds, but it doesn't know the TAI epoch; that is, it knows the leap second or seconds within a window of a few months around the current time, and it knows the relationship between its internal clock and UTC within this window, but it doesn't know all the leap seconds back to 1972. This seems to be the kind of implementation that is motivating your leap-second design, but I see a couple of problems with how struct xtime would interface to implementation X. First, implementation X can't support struct xtime's TIME_TAI, as this requires knowledge of the TAI epoch. This seems backwards to me; fundamentally, the implementation is based on TAI not UTC, and it should have some way to report this to the application. Second, implementation X can't convert timestamps outside its window to internal format, so it will reject attempts to invoke primitives involving TIME_UTC timestamps outside its window, as the internal format of those timestamps would be undefined. This seems counterintuitive to me. From the user's point of view, we'd have a system that claims to support TIME_UTC but can't convert the out-of-window value 1970-01-01 00:00:00 UTC to a TIME_UTC timestamp, even though the result is perfectly well-defined to be zero (the problem being that the result's _internal form_ is unknown). A more natural way to support such an implementation is to have the struct xtime interface supply a generalization of TIME_TAI, one with an implementation-defined epoch. This generalization would provide a more natural interface to this class of implementations, and would also support systems with complete knowledge of past leap seconds. 3. The struct xtime spec does not support applications that do not want to know about leap seconds and do not ever want to see them. This is a large class of applications, and POSIX.1 (as well as many important non-POSIX OSes) support such applications, but the struct xtime spec doesn't support them at all. This can be fixed by adding a variant of TIME_UTC that never reports leap seconds. If you combine solutions (2) and (3), then you don't need the current TIME_UTC any more. It's enough to have the generalization of TIME_TAI with implementation-defined epoch, along with the variant of TIME_UTC that never reports leap seconds. Also, once you combine solutions (2) and (3), you don't ever need struct xtime values with nsec>=1000000000. If an application wants to work properly with leap seconds, it should use the generalization of TIME_TAI and thus doesn't need nsec>=1000000000. Conversely, if the application doesn't want to know about leap seconds and doesn't ever want to see them, it should use the variant of TIME_UTC that never reports leap seconds, so it also doesn't need nsec>=1000000000. Disallowing nsec>=1000000000 simplifies things greatly. It also makes it practical to use a single 64-bit integer timestamp instead of a two-part structure. I'm working on a proposal along these lines (derived from your proposal) and would like to publish it soon.