
SM> TimeDiff has a perfectly well-defined meaning for Eq and Ord: one SM> TimeDiff is equal to another iff all the fields are respectively equal.
Yes, sure, Eq and Ord are defined by deriving (Eq, Ord, ...) but this does not make much sense if the representation for a particular duration is not unique. All I'm asking for is a unique representation for a duration and I do not see how you can do this using not uniquely defined terms like "month" and "year".
TimeDiff isn't a "duration", it's a way of specifying time offsets whose duration depends on the base to which the offset is being added. If we only had constant-duration offsets, then there would be no way to say "give me a ClockTime for this time next Wednesday". The problem is really that all the different kinds of offset are lumped into one type: there ought to be a TimeDiffSeconds, TimeDiffMonths, and so on. TimeDiffSeconds is a constant-duration offset, but TimeDiffMonths isn't. The problem with lumping them into one type is that if multiple components are non-zero, you don't know in which order to add them. The TimeExts library gives you separate differences like these, BTW. [snip]
SM> This isn't a problem with the spec, I think. A TimeDiff of "1 month" is SM> precisely a difference, which, when added to a given ClockTime, produces SM> a ClockTime which is one month later (with respect to some timezone, SM> presumably UTC since it isn't specified otherwise). That is, January SM> 12th 12:00 UTC becomes February 12th 12:00 UTC, and so on. Adding one SM> month to certain ClockTimes is meaningless: eg. adding one month to SM> January 31st doesn't work.
Unfortunately, with UTC, this goes on to make adding *anything* except seconds to certain ClockTimes (namely the instants of leap seconds, eg, what happens if you add 1 minute to 23:59:60 ? This is a perfectly legal UTC time on a day with a leap second) meaningless.
That's right, and here I'm not sure whether the right behaviour is to raise an exception or to "roll over" to the next nearest date/time. I believe TimeExts does some kind of rolling over, but I'm not sure of the exact semantics (George?).
My take would be to look at an established standard for expressing time durations (eg, ISO8601) and just adhere to that (but not the POSIX standard, please!). Personally, I think that it is unacceptable to make something like addToClockTime a partial function.
Ok, ISO8601 seems to specify only constant-duration time intervals, but allows them to be given in terms of years, months, days etc., where a month is specified to be 30 days, it seems, and similar approximations are made for the other units. This seems very odd to me, but if that's what you want... (it's possible I'm misreading the standard, or maybe I got hold of an old version though).
SM> At least, that's how I believe it is supposed to work. GHC's SM> implementation *is* completely wrong (which is perhaps where some of the SM> confusion comes from), but the TimeExts library can be used instead of SM> TimeDiffs.
Well, so you agree that the behavior of the Time module is unspecified! Of course, I'm not blaming GHC's implementation which cannot be right under these circumstances.
Yes, it's unspecified, but I also think many people misinterpret it to be more broken than it actually is.
SM> This is a perfectly reasonable definition of absolute time, we don't SM> need to talk about TAI at all, except to define what the epoch means.
Agreed! So what is epoch? Is it "Seconds since 00:00:00 on 1 Jan 1970 [TAI]"?
I guess so... GHC's implementation will be whatever the C library uses, which I assume is the one you specified above (at least on a decent implementation). Cheers, Simon