
There's been a lot of discussion here and other lists of replacing System.Time, and indeed Simon M. is working on a replacement proposal: http://www.haskell.org/~simonmar/time/NewTime.html http://www.haskell.org/~simonmar/time/NewTime.hsc Rather than talk about specific Haskell code, I'd like to discuss the measurement of time in general, how these concepts might be expressed in Haskell, and what people might want from a time library. Rather than propose anything, I want to try to ask some of the right questions. Scales of Time -------------- First of all, there are two obvious ways of measuring time. One is "clock time", "absolute time", or "atomic time", time as would be measured by a perfect clock. The standard for this is "International Atomic Time", or TAI, which is measured by an international system of atomic and maser clocks under the auspices of BIPM. TAI was established in 1955. The various clocks around the world are kept synchronised by simultaneous observation of transmissions from GPS satellites, though BIPM is considering other methods. In addition to distributing time live, BIPM issues post hoc corrections to create an even more accurate timescale. TAI is nothing more than a continuous count of "SI seconds", which are a fixed period of time defined in terms of a particular physical process. Nevertheless TAI is usually represented in "date and time" format, even as those "SI days" drift away from real Earth days. The other way is in terms of the earth's rotation against the sun. To get an accurate and even timescale, the earth's rotation is measured against the stars and distant radio sources, and then corrected for the annual orbit of the earth around the sun. Doing this at a particular place on the earth gives a version of "Universal Time" known as UT0. Despite its name, UT0 varies from place to place due to the motion of the poles. Correcting for polar motion yields UT1, which is a single scale for all places. Note that the sun itself may be up to 16 minutes off UT0 due to the "equation of time", that is, the motion of the earth on its elliptical orbit. UT1 is a continuous count of "Earth days". Since the earth does not keep perfect time, the precise length of these days varies. UT1 and TAI were synchronised at the precise beginning of 1958 as observed at Greenwich. Since then, the two have drifted apart, with UT1 days being about 2ms longer than the "SI days" (= 86400 SI seconds) of TAI. The difference between the two is currently around 32 seconds. A parameter known as "Delta T" tracks the difference: Delta T = TT - UT1 = TAI - UT1 + 32.184s The current value of Delta T is about 64s. The offset constant of 32.184s has a historical reason: that and some of the other historical details I've omitted. TT is something called "Terrestrial Time". Neither UT1 nor TAI is used for civil time, however. Instead, a timescale known as UTC was defined in 1972. Like TAI, UTC counts SI seconds, and the difference is always an integer number of seconds (currently 32). Like UT1, UTC does not drift with real Earth days, and the difference is always kept with 0.9s. This is managed by inserting or removing "leap seconds" into the timescale at the end of June or December. The IERS is responsible for determining leap seconds. Unfortunately, the earth's rotation is not very predictable. Indeed even human actions such as damming large rivers near the equator are enough to make a difference to timekeeping. As a result, the IERS gives only six months' notice of its decision to adjust UTC or not. For instance, leap seconds used to be regular insertions about every 18 months, but there hasn't been one since the one at the end of 1998. All adjustments so far have been insertions, though removals are also possible: David Mills claims his popular NTP time distribution software can handle that, though other software might potentially have problems. UTC might be thought of as an integer count of days, together with a continuous count of seconds. Most days have 86400 seconds in them, a few have 86401, and some might have 86399. Time Zones ---------- So TAI, UT1, and UTC are the most commonly used timescales. Of course, when it's daytime in one place, it's nighttime somewhere else, so local "time zones" are defined. Time in each zone is a fixed offset to UTC, usually a whole number of hours though in some zones (such as the single one for all of India) it's on a half-hour. Each zone might nominally refer to a meridian or line of longitude: while meridians are more relevant to UT1, they give some notion of the accuracy of the time in the zone as compared to the motion of the sun through the sky. The meridian for Eastern Standard Time, for instance, is at 75dW, the one for Pacific Standard Time is 120dW. Confusingly, in some zones in the northern hemisphere, or some parts of some zones, time is offset by an additional hour during some summer period. The precise days in the year vary from place to place, and the parts of the zones that are subject to this are not always simply defined. For instance, the American state of Indiana has three separate regions, with three different time behaviours: most of it uses EST without summer offset, another part uses EST with an offset in the summer, and another part uses CST with an offset in the summer. Time zones informally have three-letter acronyms, however I believe these are not standardised. Specifying the actual time difference is standard in software protocols. Calendrics ---------- A calendar is a system of naming periods of time: usually these are periods of days, though the boundary between named days may vary. A calendar may be determinate or it may involve some kind of observation, it may or may not track the year as defined in various ways, it may or may not track the period of the moon with varying degrees of accuracy, etc. It may involve one or more separate cycles, such as the seven-day "week" cycle. It may have associated with it certain "special" days that may be defined in related or unrelated ways. It's worth noting that even the length of the year is not a well-defined thing. The length of time between March equinoxes differs from the length of time between June solstices and so on, since the solstices and equinoxes are drifting relative to each other as they precess around the ellipse of the earth's orbit. Time Library ------------ So what does this mean for Haskell? Mostly that there is a very wide range of time-related needs for various applications. Ideally a standard library would help with some of these without prejudicing others. Here are some things that I think ought to be kept in mind even though some of them may be beyond the scope of a standard library, together with some issues: * Basic types for time Should there be different types for TAI/UT1/UTC? What about separate difference types? What resolution should be used? Should we use fixed-point numeric types? Should time types be parameterised by underlying numeric type? * Converting between timescales TAI/UTC conversion means knowing and predicting leap-seconds. This information changes over the years. What about the backwards extension of UTC to before it was created? TAI/UT1 conversion means a function for the earth's rotation. This too is dependent on changing information. What sort of approximations would be needed? If both conversions are provided, would it be appropriate to provide guarantees about the calculated difference between UT1 and UTC? * Converting between different zones Should a time-zone be a first-class object? What type would it use, would a difference type be appropriate? * Calculating summertime zone adjustments This is probably a bit much for a standard library, especially as official definitions change occasionally. Nevertheless, some thought about this may be helpful. For instance, when Seattle moves from PST to PDT, has it actually moved time zones? Or is it in the same time zone, but switched "time offsets"? What's the best terminology? * Getting the current time and zone Which timescales should be available? Different platforms may have different information available. * Calendrics What about functions for working with Gregorian calendar information? I'm guessing other calendars should probably be left to others. * Displaying and parsing time in different zones Which standard formats should be covered? Would a field-based "printf" system be useful here? * General organisation Is it worth splitting it into more than one module? -- Ashley Yakeley, Seattle WA

Rather than talk about specific Haskell code, I'd like to discuss the measurement of time in general, how these concepts might be expressed in Haskell, and what people might want from a time library. Rather than propose anything, I want to try to ask some of the right questions.
Wow, thanks for the impressive essay! I think we should also consider some of the things people might want to do with these times. In particular, people often want to compute with time differences: next week, next month, next year, etc. These are calendar operations, and defining precisely what they mean in edge cases is often tricky. Even discounting leap seconds and the like, "next month" is sometimes 28 days into the future, sometimes 29, sometimes 30, and sometimes 31 - and sometimes makes little sense: when is "31 January 2005 plus one month"? Similarly for "next year". And the decisions will be different for different applications - "plus one year" when computing a birthday or anniversary will be different from "plus one year" when computing interest on a loan. Any "time difference" type must deal carefully with these issues, and must document its behaviour on the edge cases. --KW 8-)

Keith Wansbrough wrote:
Rather than talk about specific Haskell code, I'd like to discuss the measurement of time in general, how these concepts might be expressed in Haskell, and what people might want from a time library. Rather than propose anything, I want to try to ask some of the right questions.
Wow, thanks for the impressive essay!
I second that -- it was a pleasant read and a very nice summary. Considering all the issues, it seems important to be pragmatic about the Time library: The first attempt at the Time library should probably focus on the basics that we clearly understand: TAI and UTC, and maybe time zones. The more tricky stuff, like calendars, and "next year" can than be dealt with later, on top of the well understood libraries. -- Daan.
I think we should also consider some of the things people might want to do with these times. In particular, people often want to compute with time differences: next week, next month, next year, etc. These are calendar operations, and defining precisely what they mean in edge cases is often tricky. Even discounting leap seconds and the like, "next month" is sometimes 28 days into the future, sometimes 29, sometimes 30, and sometimes 31 - and sometimes makes little sense: when is "31 January 2005 plus one month"? Similarly for "next year". And the decisions will be different for different applications - "plus one year" when computing a birthday or anniversary will be different from "plus one year" when computing interest on a loan.
Any "time difference" type must deal carefully with these issues, and must document its behaviour on the edge cases.
--KW 8-)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Keith Wansbrough
In particular, people often want to compute with time differences: next week, next month, next year, etc. These are calendar operations, and defining precisely what they mean in edge cases is often tricky. Even discounting leap seconds and the like, "next month" is sometimes 28 days into the future, sometimes 29, sometimes 30, and sometimes 31 - and sometimes makes little sense: when is "31 January 2005 plus one month"?
We should look how other languages solve that. C provides only mktime, conversion from a broken-down time which lets out-of-range values adjust larger units. This is not sufficient for implementing adjustment of a single unit in the intuitive way: it can't be done by the naive algorithm of incrementing the value and normalizing the resulting date. For example 30 April + 1 day should be 1 May, but 31 March + 1 month should be 30 April. Yet both calculations would ask to normalize 31 April, and the normalization function doesn't know which out-of-range units have been just set explicitly and should be wrapped, and which result from changing the larger unit and should be clipped. Here is the Java interface: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html and the .NET interface: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... Both systems allow to adjust individual fields. Java is more complex here, it also provides an interface for rolling with wraparound. Neither language provides a type for representing a timespan which is not a well-defined number of seconds. Java has no timespan type at all, while the .NET TimeSpan can be viewed only in units not larger than a day - no months or years. These languages provide metods for adjustments of individual fields, without materializing the timespan as a whole. * * * .NET provides some calendars other than the Gregorian calendar, while Java does not (but it leaves room for them: there is an abstract class Calendar whose only standard subclass is GregorianCalendar): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... * * * Java attacks a problem which .NET doesn't: specifying the date in terms of fields which are usually considered derived from other fields, like day of week and day of year: | If there is any conflict in calendar field values, Calendar gives | priorities to calendar fields that have been set more recently. The | following are the default combinations of the calendar fields. The | most recent combination, as determined by the most recently set | single field, will be used. | | For the date fields: | | YEAR + MONTH + DAY_OF_MONTH | YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK | YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK | YEAR + DAY_OF_YEAR | YEAR + DAY_OF_WEEK + WEEK_OF_YEAR | | For the time of day fields: | | HOUR_OF_DAY | AM_PM + HOUR Since there are various rules about numbering weeks of a year in use, attacking the above problem requires to let the programmer specify the rule. In Java it is done by setting the minimal number of days in the first week of a year, while .NET provides enum CalendarWeekRule with values FirstDay, FirstFullWeek and FirstFourDayWeek, corresponding to the three values actually in use (1, 7 and 4 respectively). * * * For my language Kogut I designed a small interface which I believe is rich enough. A date can be constructed out of fields year, month, day, hour, minute, second, and tick (nanosecond in my implementation). A date also appears to have fields dayOfYear and dayOfWeek, but they are always computed rather than provided on input. There are also timezones; I won't describe them here now. Out-of-range fields are normalized and cause adjustment of other fields on construction. Dates are immutable. The generic operation of functional update of selected fields of a record has a specialized implementation for dates. Since it knows which fields are being set and which are being kept from the date of reference, it can distinguish between changing the day of 30 April to 31 (it gives 1 May) and changing the month of 31 March to April (it gives 30 April). So there are no operations for adding a specific amount to a field, since setting it to the old value + the delta has the right semantics, contrary to mktime. There are no operations for rolling of fields - it's easy enough to perform the modulo by hand. There is no interface for getting or setting the week of a year/month, because they would require additional complexity of selecting the rules to use, and it's easy enough to implement them in terms of the day of the year/month and the day of the week. There is no interface for setting the day of the year, because it's equivalent to setting the corresponding day of January. Time is in 24 hour format - Java provides both formats at once, but I claim that it's easy enough to convert it by hand when needed. There is no type for a timespan, and there will not be. It's easy enough to adjust individual fields. I haven't yet implemented formatting nor parsing of dates. There are too many non-obvious design decisions here. But this will have to be done at some time. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/

On Mon, 24 Jan 2005, Marcin 'Qrczak' Kowalczyk wrote:
We should look how other languages solve that.
A famous solution which evolved on Amiga computers: http://www.datelib.de/index.shtml.en

On Monday 24 January 2005 15:15, Henning Thielemann wrote:
On Mon, 24 Jan 2005, Marcin 'Qrczak' Kowalczyk wrote:
We should look how other languages solve that.
A famous solution which evolved on Amiga computers: http://www.datelib.de/index.shtml.en
The advertisement at least sounds like this would be it. I'll take a closer look at it. Ben

On Mon, Jan 24, 2005 at 02:16:16PM +0100, Marcin 'Qrczak' Kowalczyk wrote:
Keith Wansbrough
writes: In particular, people often want to compute with time differences: next week, next month, next year, etc. These are calendar operations, and defining precisely what they mean in edge cases is often tricky. Even discounting leap seconds and the like, "next month" is sometimes 28 days into the future, sometimes 29, sometimes 30, and sometimes 31 - and sometimes makes little sense: when is "31 January 2005 plus one month"?
We should look how other languages solve that.
The best time library I've used is Perl's DateTime. (Anyone who thinks that everything in Perl is a bad hack, please suspend judgement for a minute!) It has DateTime, DateTime::Duration, and DateTime::TimeZone classes (along with a host of supporting players, such as the handy DateTime::Span), and addresses the various ambiguities. (Another example not yet discussed here: The difference between two times can be expressed in years, days, hours, or seconds, so the library lets you choose.) I believe it gets all the date math right, including leap seconds. It is the result of considerable development, use, and experience with other time libraries. The project is at http://datetime.perl.org/ and if you click the modules link, you can read the documentation. (As I write, search.cpan.org seems to be dead, so you'll have to wait for the documentation. The FAQ might be useful in the mean time.) Andrew

Andrew Pimlott
The best time library I've used is Perl's DateTime. (Anyone who thinks that everything in Perl is a bad hack, please suspend judgement for a minute!) It has DateTime, DateTime::Duration, and DateTime::TimeZone classes (along with a host of supporting players, such as the handy DateTime::Span), and addresses the various ambiguities. (Another example not yet discussed here: The difference between two times can be expressed in years, days, hours, or seconds, so the library lets you choose.) I believe it gets all the date math right, including leap seconds. It is the result of considerable development, use, and experience with other time libraries.
The project is at
and if you click the modules link, you can read the documentation.
There certainly seem to be a lot of good ideas here. In addition to DateTime and DateTime::Span there are sets DateTime::Set and DateTime::SpanSet for representing various kinds of sets of time. Various events and calendars make use of these. -- Ashley Yakeley, Seattle WA

On Monday 24 January 2005 11:27, Keith Wansbrough wrote:
Rather than talk about specific Haskell code, I'd like to discuss the measurement of time in general, how these concepts might be expressed in Haskell, and what people might want from a time library. Rather than propose anything, I want to try to ask some of the right questions.
Wow, thanks for the impressive essay!
Yes, that was quite interesting to read.
I think we should also consider some of the things people might want to do with these times. In particular, people often want to compute with time differences: next week, next month, next year, etc. These are calendar operations, and defining precisely what they mean in edge cases is often tricky. Even discounting leap seconds and the like, "next month" is sometimes 28 days into the future, sometimes 29, sometimes 30, and sometimes 31 - and sometimes makes little sense: when is "31 January 2005 plus one month"?
There are some references here. For instance, I remember reading that in Germany the term 'in one month' is defined by civil law to be the same day (number) in the next month. If such a day does not exist, the nearest existing day in this month is taken, i.e. with regard to March 31, 'one month later' is April 30. Observing such laws or customs would be valuable for commercial applications. But different countries may have different customs (not to mention international law). Such things should be implementable on top of a general purpose library in a modular way. Ben

Just a thought: I think we all agree on having Time as an Integer or similar representing time with some particular resolution. The question seems to be how to deal with CalendarTime, defined as a record with fields for the various components found in a human-type time stamp. I wonder if it would be worthwhile to pursue a slightly different approach? The rationale goes as such: we use a calendar and clock not necessarily to mark points in time, but to be able to point to some particular day, month, hour, etc. Would it be an idea to define something like (very rough draft here): data T = Y Int | M Int T | Wy Int T | Wm Int T | Dy Int T | Dm Int T | Dw Int T | Hr Int T | Min Int T deriving (Eq,Show) The idea is that time can be a year, or a month in some year, or a week in some year (yes, I know it's ambigous), week in month (in year), day in year, day in month in year, and so on. Clearly, deriving Eq is not a good idea - I think Eq should consider a Dy and Dm equal if they refer to the same day. Now, some functions to construct values of Time could be year y = Y y month m (Y y) = M m (Y y) And why not create multiple values in one go: months (Y y) = [M m (Y y) | m <- [1..12]] days (Y y) = [Dy d (Y y) | d <- [1..(if y `mod` 4 == 0 then 366 else 365)]] days (M m yy@(Y y)) | m `elem` [1,3,5,7,8,10,12] = [Dm d (M m yy) | d <- [1..31]] | m == 2 = [Dm d (M m yy) | d <- [1..if y `mod` 4 == 0 then 29 else 28]] | otherwise = [Dm d (M m yy) | d <- [1..30]] Now it's easy to get all the days of December this year: *Main> days $ last $ months $ year 2005 [Dm 1 (M 12 (Y 2005)),Dm 2 (M 12 (Y 2005)),Dm 3 (M 12 (Y 2005)),Dm 4 (M 12 (Y 2005)),Dm 5 (M 12 (Y 2005)),Dm 6 (M 12 (Y 2005)),Dm 7 (M 12 (Y 2005)),Dm 8 (M 12 (Y 2005)) [...] So, if my local Linux user group has meetings the last Thursday each month, this can be written something like map (last . filter isThursday . days) (months $ year 2005) It's just an idea, but perhaps worth considering? Comments welcome! -kzm -- If I haven't seen further, it is by standing in the footprints of giants

At 08:56 25/01/05 +0100, Ketil Malde wrote:
I think we all agree on having Time as an Integer or similar representing time with some particular resolution. The question seems to be how to deal with CalendarTime, defined as a record with fields for the various components found in a human-type time stamp.
Just for the record, my silence is not consent on this. I believe I'm in a minority and don't challenge the majority decision, but I would prefer a date/time representation based on a pair (days,ticks), where ticks is a count of some suitable fraction of a second. My reasons have been recorded here previously ... I'll dig out a reference if anyone cares. #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Graham Klyne
At 08:56 25/01/05 +0100, Ketil Malde wrote:
I think we all agree on having Time as an Integer or similar representing time with some particular resolution. The question seems to be how to deal with CalendarTime, defined as a record with fields for the various components found in a human-type time stamp.
Just for the record, my silence is not consent on this. [..] (days,ticks)
This (almost) falls in under "similar". Unless you feel this model subsumes the "calendar" type of time, in which case I'd like to see the reference as well. -kzm -- If I haven't seen further, it is by standing in the footprints of giants

At 21:41 25/01/05 +0100, Ketil Malde wrote:
Graham Klyne
writes: At 08:56 25/01/05 +0100, Ketil Malde wrote:
I think we all agree on having Time as an Integer or similar representing time with some particular resolution. The question seems to be how to deal with CalendarTime, defined as a record with fields for the various components found in a human-type time stamp.
Just for the record, my silence is not consent on this. [..] (days,ticks)
This (almost) falls in under "similar". Unless you feel this model subsumes the "calendar" type of time, in which case I'd like to see the reference as well.
If (days,ticks) counts as similar, then I agree that I'm not a counterexample to your original assertion. ... Turning to the more general discussion of time... how complex a time library do we want? What sorts of things do folks actually want to do with time values most of the time? I think (intuitively, without hard evidence) that a simple library can handle many of the requirements, such as: - accurately representing duration of "short" processes (e.g. program executions) - approximately representing duration of longer processes - representing the date/time of human-scale events I regard timezones (as opposed to timezone offsets from UTC) and leap seconds as specialized issues that don't impact many of the common uses for date/time. A time library shouldn't preclude sensible implementations of these, but I don't think it needs to include them all. In summary, I suggest: keep it simple. #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Graham Klyne wrote:...
I regard timezones (as opposed to timezone offsets from UTC) and leap seconds as specialized issues that don't impact many of the common uses for date/time. A time library shouldn't preclude sensible implementations of these, but I don't think it needs to include them all.
It will need proper timezone information. For example if it does not include the proper information for UK daylight savings time, my Personal-Video-Recorder box, written in Haskell, will record the wrong programs in summer. Keean.

In article <5.1.0.14.2.20050125161230.02e21620@127.0.0.1>,
Graham Klyne
I believe I'm in a minority and don't challenge the majority decision, but I would prefer a date/time representation based on a pair (days,ticks), where ticks is a count of some suitable fraction of a second. My reasons have been recorded here previously ... I'll dig out a reference if anyone cares.
I think (days,ticks) might be worth examining for UTC time, since UTC has a variable number of seconds for each day (usually 86400, but may be one more or one less). -- Ashley Yakeley, Seattle WA

Ketil Malde
Would it be an idea to define something like (very rough draft here):
data T = Y Int | M Int T | Wy Int T | Wm Int T | Dy Int T | Dm Int T | Dw Int T | Hr Int T | Min Int T deriving (Eq,Show)
The idea is that time can be a year, or a month in some year, or a week in some year (yes, I know it's ambigous), week in month (in year), day in year, day in month in year, and so on.
This seems to be equivalent to DateTime::Incomplete in Perl's DateTime. If so I'd consider representing it more like this: data T = MkT y :: Maybe Int m :: Maybe Int wy :: Maybe Int wm :: Maybe Int ... -- Ashley Yakeley, Seattle WA

Ashley Yakeley
data T = Y Int | M Int T | Wy Int T | Wm Int T | Dy Int T | Dm Int T | Dw Int T | Hr Int T | Min Int T deriving (Eq,Show)
The idea is that time can be a year, or a month in some year, or a week in some year (yes, I know it's ambigous), week in month (in year), day in year, day in month in year, and so on.
This seems to be equivalent to DateTime::Incomplete in Perl's DateTime.
(That's a pretty odd name for it.)
If so I'd consider representing it more like this:
data T = MkT y :: Maybe Int m :: Maybe Int wy :: Maybe Int wm :: Maybe Int ...
Yes, that's a possibility. And of course, it is possible to leave fields undefined in a record as well. I'd like there to be a good way of using the type system to ensure that the dates are "sensible" (e.g. you don't specify both wm and wy etc), but I'm not sure how. Note that MkT is not quite similar, in my suggestion, you would need at least to specify the year to have the precise date. So if I want to specify my birthday, the natural representation would be as a function: \(Y y) -> (Dm 19 (M 5 (Y y))) Perhaps another approach, making better use of the type system, would be to say something like: data Year = Y Int data Month = M Int Year data Week = Wy Int Year | Wm Int Month data Day = Dy Int Year | Dm Int Month | Dw Int Week : data Second = S Int Hour | S Int Day -- of year, for UTC I guess I'm just rambling, and should sit down and think things through a bit. Or at least post to -cafe :-) -kzm -- If I haven't seen further, it is by standing in the footprints of giants
participants (11)
-
Andrew Pimlott
-
Ashley Yakeley
-
Benjamin Franksen
-
Daan Leijen
-
Graham Klyne
-
Graham Klyne
-
Henning Thielemann
-
Keean Schupke
-
Keith Wansbrough
-
Ketil Malde
-
Marcin 'Qrczak' Kowalczyk