Apologies for following up my own posting, but I don't want to lose the thread here. I have edited the quoted text below for clarity.
Nathan Myers wrote:
The problem with the mktime model is that conversions between civil time and timestamps can result in 2, 1, or <1 valid conversions ...
... it's a rare wall clock, legal document, train schedule or airline ticket that indicates UTC offset, and when it does it's likely to be wrong, especially during the "interesting" times. ... The problem that normally arises is that someone enters a date/time and I want a numeric real-time value. I distinguish the following troublesome cases:
1. It's in spring and they enter 02:30, and that time doesn't exist, but there's a good guess (e.g. equiv. to 03:30) for what they probably meant. (There's a corresponding case for leap seconds.) 2. In spring they enter 03:30, which might be correct, but they might well have meant 04:30 because they failed to reset their clock. 3. In autumn, they enter 01:30; did they mean the first time it happened that day or the second? Either is equally valid. 4. (Also in autumn) If they enter 02:30, did they mean officially 02:30, or did they mean the second 01:30?
I believe that conversions should yield a struct containing a reference timestamp, followed by up to four offsets tagged with official wall-clock offset, interpretation, and confidence values. For example, in the cases above, and ignoring leap seconds for the moment, we would get 0. Unambiguous time, e.g. 04:30 morning of a time change t0=123456789 offset 0: 0 sec; wall-clock offset: -3600 sec; interpretation: unambiguous; confidence: certain offset 0: -3600 sec; wall-clock offset: -3600 sec. interpretation: suggested substitute; confidence: doubtful 1. Spring ambiguity, enter 02:30 when it doesn't exist because civil time proceeded 01:59:59 -> 03:00:00. (Or 02:00:00 to 03:00:01? I don't know.) t0=123456789 offset 0: 0 sec; wall-clock offset: -3600 sec. interpretation: suggested substitute; confidence: doubtful 2. Spring ambiguity, enter 02:30 when it doesn't exist because civil time proceeded 01:59:59 -> 03:00:00 (or whatever). t0=123456789 offset 0: 0 sec; wall-clock offset: 0 sec. interpretation: official choice; confidence: Nominally unambiguous offset 1: -3600 sec; wall-clock offset: 0 sec. interpretation: suggested substitute; confidence: doubtful 3. Autumn ambiguity, enter 01:30 on morning when civil time proceeds from 01:59:59 to 01:00; is it the first or second 01:30 event? t0=123456789 offset 0: 0 sec; wall-clock offset: 3600 sec. interpretation: ambiguous choice; confidence: equal alternative offset 1: 3600 sec; wall-clock offset: 0 sec. interpretation: ambiguous choice; confidence: equal alternative 4. Autumn, enter 02:30, same morning as above; did they mean the official 02:30, or did they mean the second 01:30 because they failed to reset their clock? t0=123456789 offset 0: 0 sec; wall-clock offset: 0 sec. interpretation: official choice; confidence: Nominally unambiguous offset 1: 3600 sec; wall-clock offset: 0 sec. interpretation: unofficial choice; confidence: Possible alternative For each case above one might have up to two more entries corresponding to leap-second ambiguities. The detailed semantics of all the possible "interpretation" and "confidence" tags must be nailed down. This might end up looking sort of like the following C struct layout, using deliberately unsatisfactory names for exposition: typedef ... time_stamp; /* something more-or-less numeric */ typedef enum { official, unofficial, ambiguous, suggested } time_meaning; typedef enum { nominal, alternative, possible, doubtful } time_confidence; struct time_interpretation { int offset; /* limited to +/- 3601 */ long wall_offset; /* limited to +/- 43200 */ time_meaning meaning; time_confidence confidence; }; struct time_from_civil { time_stamp reference_time; int interpretation_count; /* range 0-4 */ time_interpretation interpretation[4]; }; (I've neglected leap-second ambiguity interpretations because they would reduce the clarity of the exposition.) The conversion function might look like: int time_convert(const struct tm *, const time_zone *, time_from_civil *); I think an interface like this would encapsulate knowledge about time conversion issues, exposing a high-level view of the possible real-time values implied by wall-clock time records. I think it would lead to better, more robust interfaces for conversions, and reduce programmer errors. Comments? Nathan Myers ncm@cantrip.org