
This seems to be roughly where we're at with the time libraries. It's now three modules, Clock, LeapSeconds, and Calendar. Most people will have no need for LeapSeconds. I've added two more things which haven't been discussed much. The first is a getCPUTime function that returns the current "CPU time". This has an arbitrary base, but it doesn't hiccup. The Unix interface for this is a "clock()" function that returns time in some unit, and CLOCKS_PER_SECOND, which is a constant to convert to seconds. I'm assuming there's a Windows equivalent to this. The second thing is a type-synonym of Rational for Julian dates. Julian dates are a standard representation of UT1, where one unit is one day, and UT1 is a good choice for representing Earth-based times in the far past or future continuously. System.Time.Clock: * UTC arithmetic * types or type-synonyms for Julian days and dates (for UT1) * getting the current UTC time * getting the current "CPU time" System.Time.LeapSeconds: * TAI arithmetic * leap-second table type * conversion between UTC and TAI with table System.Time.Calendar (largely undiscussed so far): * time zones * getting the locale time zone * converting times to Gregorian "calendrical" format * calendrical arithmetic e.g. one month after March 31st * possibly "incomplete dates" e.g. "May 1" for all years * parsing and showing dates and times Left for other libraries (standard or user): * sunrise/sunset, moon phase, solstices & equinoxes, etc. * figuring out time zone from position on Earth * civil summertime zone adjustment calculation, interface to zoneinfo database * calendar systems other than Gregorian * generalised sets over time e.g. "2pm-4pm every 4th Saturday of the month" module System.Time.Clock ( ... ) where -- | standard Julian count of Earth days type JulianDay = Integer newtype DiffTime = MkDiffTime Integer timeToSISeconds :: DiffTime -> Rational siSecondsToTime :: Rational -> DiffTime data UTCTime = MkUTCTime JulianDay DiffTime newtype UTCDiffTime = MkUTCDiffTime Integer utcTimeToUTCSeconds :: UTCDiffTime -> Rational utcSecondsToUTCTime :: Rational -> UTCDiffTime addUTCTime :: UTCDiffTime -> UTCTime -> UTCTime diffUTCTime :: UTCTime -> UTCTime -> UTCDiffTime ...more arithmetic on UTCDiffTime... -- | standard Julian dates for UT1, 1 = 1 day type JulianDate = Rational getCurrentTime :: IO UTCTime getCPUTime :: IO DiffTime -- | most people won't need this module module System.Time.LeapSeconds ( ... ) where -- | TAI type AbsoluteTime = MkAbsoluteTime Integer addAbsoluteTime :: DiffTime -> AbsoluteTime -> AbsoluteTime diffAbsoluteTime :: AbsoluteTime -> AbsoluteTime -> DiffTime -- | TAI - UTC during this day type LeapSecondTable = JulianDay -> Int utcDayLength :: LeapSecondTable -> JulianDay -> DiffTime utcToTAITime :: LeapSecondTable -> UTCTime -> TAITime taiToUTCTime :: LeapSecondTable -> TAITime -> UTCTime module System.Time.Calendar ... TBD ... -- Ashley Yakeley, Seattle WA

On Feb 9, 2005, at 6:24 AM, Ashley Yakeley wrote:
This seems to be roughly where we're at with the time libraries. It's now three modules, Clock, LeapSeconds, and Calendar. Most people will have no need for LeapSeconds.
I've added two more things which haven't been discussed much. The first is a getCPUTime function that returns the current "CPU time". This has an arbitrary base, but it doesn't hiccup. The Unix interface for this is a "clock()" function that returns time in some unit, and CLOCKS_PER_SECOND, which is a constant to convert to seconds. I'm assuming there's a Windows equivalent to this.
The second thing is a type-synonym of Rational for Julian dates. Julian dates are a standard representation of UT1, where one unit is one day, and UT1 is a good choice for representing Earth-based times in the far past or future continuously.
Are the Julian Dates to be true Julian dates (date changes at noon) or Modified Julian Dates (changes at midnight)? Greg

In article <5d8a02884c87a98fb6e4f4ae8c98d5a9@comcast.net>,
Gregory Wright
Are the Julian Dates to be true Julian dates (date changes at noon) or Modified Julian Dates (changes at midnight)?
I'd originally thought JD, but MJD might be better if zero starts at UTC midnight. In either case JulianDay and JulianDate should match. Probably we should call them ModJulianDay and ModJulianDate if so. Which is more commonly used? -- Ashley Yakeley, Seattle WA

On Feb 9, 2005, at 9:44 PM, Ashley Yakeley wrote:
In article <5d8a02884c87a98fb6e4f4ae8c98d5a9@comcast.net>, Gregory Wright
wrote: Are the Julian Dates to be true Julian dates (date changes at noon) or Modified Julian Dates (changes at midnight)?
I'd originally thought JD, but MJD might be better if zero starts at UTC midnight. In either case JulianDay and JulianDate should match. Probably we should call them ModJulianDay and ModJulianDate if so.
Which is more commonly used?
MJD is most commonly used, especially among people with a professional interest in timekeeping. The definition is MJD = JD - 2400000.5 Where the JD is the day count from the Julian Epoch, 4712 BCE January 1 at Greenwich Noon. Julian Dates are represented as decimal fractions. The _Explanatory Supplement_ states: "The midnight that begins the civil day is specified by subtracting 0.5 from the Julian Date at noon." So MJD lags the JD by half a day. Greg
-- Ashley Yakeley, Seattle WA
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Seems very nice, I would still argue that Calendars can be a class as all calendars will end up implementing the same (or similar) functions... but the work of defining a generalised interface to calendars is harder than defining a specific interface to a single calendar... In reality I don't think it can be done until several calendars have been implemented. Perhaps defining the library for UTC first, then if other calendars are implemented later a generalised interface can be defined later? Keean. Ashley Yakeley wrote:
This seems to be roughly where we're at with the time libraries. It's now three modules, Clock, LeapSeconds, and Calendar. Most people will have no need for LeapSeconds.
I've added two more things which haven't been discussed much. The first is a getCPUTime function that returns the current "CPU time". This has an arbitrary base, but it doesn't hiccup. The Unix interface for this is a "clock()" function that returns time in some unit, and CLOCKS_PER_SECOND, which is a constant to convert to seconds. I'm assuming there's a Windows equivalent to this.
The second thing is a type-synonym of Rational for Julian dates. Julian dates are a standard representation of UT1, where one unit is one day, and UT1 is a good choice for representing Earth-based times in the far past or future continuously.
System.Time.Clock:
* UTC arithmetic
* types or type-synonyms for Julian days and dates (for UT1)
* getting the current UTC time
* getting the current "CPU time"
System.Time.LeapSeconds:
* TAI arithmetic
* leap-second table type
* conversion between UTC and TAI with table
System.Time.Calendar (largely undiscussed so far):
* time zones
* getting the locale time zone
* converting times to Gregorian "calendrical" format
* calendrical arithmetic e.g. one month after March 31st
* possibly "incomplete dates" e.g. "May 1" for all years
* parsing and showing dates and times
Left for other libraries (standard or user):
* sunrise/sunset, moon phase, solstices & equinoxes, etc.
* figuring out time zone from position on Earth
* civil summertime zone adjustment calculation, interface to zoneinfo database
* calendar systems other than Gregorian
* generalised sets over time e.g. "2pm-4pm every 4th Saturday of the month"
module System.Time.Clock ( ... ) where
-- | standard Julian count of Earth days type JulianDay = Integer
newtype DiffTime = MkDiffTime Integer
timeToSISeconds :: DiffTime -> Rational
siSecondsToTime :: Rational -> DiffTime
data UTCTime = MkUTCTime JulianDay DiffTime
newtype UTCDiffTime = MkUTCDiffTime Integer
utcTimeToUTCSeconds :: UTCDiffTime -> Rational
utcSecondsToUTCTime :: Rational -> UTCDiffTime
addUTCTime :: UTCDiffTime -> UTCTime -> UTCTime
diffUTCTime :: UTCTime -> UTCTime -> UTCDiffTime
...more arithmetic on UTCDiffTime...
-- | standard Julian dates for UT1, 1 = 1 day type JulianDate = Rational
getCurrentTime :: IO UTCTime
getCPUTime :: IO DiffTime
-- | most people won't need this module module System.Time.LeapSeconds ( ... ) where
-- | TAI type AbsoluteTime = MkAbsoluteTime Integer
addAbsoluteTime :: DiffTime -> AbsoluteTime -> AbsoluteTime
diffAbsoluteTime :: AbsoluteTime -> AbsoluteTime -> DiffTime
-- | TAI - UTC during this day type LeapSecondTable = JulianDay -> Int
utcDayLength :: LeapSecondTable -> JulianDay -> DiffTime
utcToTAITime :: LeapSecondTable -> UTCTime -> TAITime
taiToUTCTime :: LeapSecondTable -> TAITime -> UTCTime
module System.Time.Calendar ... TBD ...

Ashley Yakeley wrote:
data UTCTime = MkUTCTime JulianDay DiffTime newtype UTCDiffTime = MkUTCDiffTime Integer utcTimeToUTCSeconds :: UTCDiffTime -> Rational utcSecondsToUTCTime :: Rational -> UTCDiffTime addUTCTime :: UTCDiffTime -> UTCTime -> UTCTime diffUTCTime :: UTCTime -> UTCTime -> UTCDiffTime
A good draft. Questions: 1. Are DiffTime and UTCDiffTime specified as picoseconds, or must we use timeToSISeconds when we need a time difference with units? 2. In a UTCTime, is the DiffTime limited to 86400 or 86401 or unlimited? I don't see an overall benefit from distinguishing UTCDiffTime from DiffTime. The representation of UTCTime forces them to have identical precision and often to have the same meaning. The names timeToSISeconds and siSecondsToTime might be better without the SI, as timeToSeconds and secondsToTime. Our clocks will be having hiccups when leap seconds arrive so they won't always tell SI seconds. Also times prior to UTC have seconds of different lengths. The addUTCTime and diffUTCTime functions are a concern because your earlier email said that they should ignore leap seconds. That is plenty useful but it's likely to bite a naive user. I'd like them to be called addUTCTimeNoLeap and diffUTCTimeNoLeap.

In article <200502092100.00086.p.turner@computer.org>, Scott Turner
A good draft. Questions: 1. Are DiffTime and UTCDiffTime specified as picoseconds, or must we use timeToSISeconds when we need a time difference with units?
It seems people prefer to hide the constructor, in which case you'd have to use the conversion functions. We could have Integer "picoseconds" conversion functions as well, perhaps.
2. In a UTCTime, is the DiffTime limited to 86400 or 86401 or unlimited?
The maximum value is 86401*10^12-1. The minimum value is 0.
I don't see an overall benefit from distinguishing UTCDiffTime from DiffTime.
The representation of UTCTime forces them to have identical precision and often to have the same meaning.
The idea is that a UTCDiffTime ignores leap seconds, and DiffTime doesn't. Thus I can express the concept "three hours UTC" as a UTCDiffTime, which will take us from 11:00:00pm to 2:00:00am across a leap second. By contrast, "three SI hours" is a fixed period of time, and would be 11:00:00pm to 1:59:59am if a leap-second intervenes.
The names timeToSISeconds and siSecondsToTime might be better without the SI, as timeToSeconds and secondsToTime. Our clocks will be having hiccups when leap seconds arrive so they won't always tell SI seconds. Also times prior to UTC have seconds of different lengths.
timeToSISeconds and siSecondsToTime work entirely with DiffTime, which is cleanly monotonic and doesn't hiccup. The difference between to TAI times is a DiffTime and is measured in fixed unvarying SI seconds.
The addUTCTime and diffUTCTime functions are a concern because your earlier email said that they should ignore leap seconds. That is plenty useful but it's likely to bite a naive user. I'd like them to be called addUTCTimeNoLeap and diffUTCTimeNoLeap.
The idea is that if you stay entirely within the UTC "world", getting UTC time from the clock, and using UTCTime and UTCDiffTime, and printing out the UTC time, all your calculations should come out as expected. The only difference is that the scale is not monotonic with real time. You cannot in any case cross into the TAI "world" without a LeapSecondTable. -- Ashley Yakeley, Seattle WA

The MkUTCTime constructor is exposed. Right? On 2005 February 09 Wednesday 23:46, Ashley Yakeley wrote:
The idea is that a UTCDiffTime ignores leap seconds, and DiffTime doesn't. Thus I can express the concept "three hours UTC" as a UTCDiffTime, which will take us from 11:00:00pm to 2:00:00am across a leap second. By contrast, "three SI hours" is a fixed period of time, and would be 11:00:00pm to 1:59:59am if a leap-second intervenes.
The "three hours UTC" doesn't fit my mental model. Perhaps others find it natural. Compare it to leap days. Would we support a concept of "three years Gregorian" as a count of 1095 days, which would take us from 2003 Jan 1 to 2006 Jan 1 across the leap day in 2004? That is, 2003-Jan-1 `addDays` (3*365) == 2005-Dec-31 2003-Jan-1 `addDays` (3 * daysPerGregorianYear) == 2006-Jan-1 No, daysPerGregorianYear is obviously problematic. To do a year-based calculation, you would have addYears, as in 2003-Jan-1 `addYears` 3 == 2006-Jan-1. UTCDiffTime as a _distinct_ type has the same problem. It is only less obvious because leap seconds are less familiar and smaller in magnitude than leap days. The "three hours" concept should be supported directly, perhaps in the Calendar module. It shouldn't depend on 1 hour == 3600 seconds. I don't see why a distinction between DiffTime and UTCDiffTime would be beneficial.

Ashley Yakeley
System.Time.Clock:
* UTC arithmetic * types or type-synonyms for Julian days and dates (for UT1) * getting the current UTC time
(I'd call these -- anything that maps SI seconds to other structures, really -- calendars, but I guess I've said so enough times already :-)
* getting the current "CPU time"
Isn't this very system dependent? And isn't times(2) a better choice than clock(3)? How do these behave in the presence of leap seconds? I.e. if I clock() a computation, do I get the same result as the difference of gettimeofday()s before and after times CPU utilization, or do I get the correct times, and the consequential a leap-second offset compared to gettimeofday? I'm not able to find any information on this; I assume these functions deal in (non-linear) POSIX time, since you want them in the same module? (I would put everyting to do with performance meausrements in a different module. Although, I guess if we only target POSIX systems, this is all right. The consensus seems to be to wed time to POSIX.) -kzm -- If I haven't seen further, it is by standing in the footprints of giants

In article <87k6pgacrj.fsf@sefirot.ii.uib.no>,
Ketil Malde
* UTC arithmetic * types or type-synonyms for Julian days and dates (for UT1) * getting the current UTC time
(I'd call these -- anything that maps SI seconds to other structures, really -- calendars, but I guess I've said so enough times already :-)
I see a calendar as something that maps UTCTime to other structures. -- Ashley Yakeley, Seattle WA

Ashley Yakeley wrote:
In article <87k6pgacrj.fsf@sefirot.ii.uib.no>, Ketil Malde
wrote: * UTC arithmetic * types or type-synonyms for Julian days and dates (for UT1) * getting the current UTC time
(I'd call these -- anything that maps SI seconds to other structures, really -- calendars, but I guess I've said so enough times already :-)
I see a calendar as something that maps UTCTime to other structures.
I still think a calendar only makes sense mapping TAI time to other structures, including UTC time. There really are good reasons that other systems have implemented it this way. The bias should be towards implementing the structures in the way that those who have studied the problem at great length have concluded. UTC time itself may, or may not, in any given instant, be corrected at those times when correction is needed. The simple fact that UTC time is not monotonically increasing causes a whole host of difficulties. I see no advantage to not only reinventing this wheel, but in using a different wheel.

Seth Kurtzberg
I still think a calendar only makes sense mapping TAI time to other structures, including UTC time. There really are good reasons that other systems have implemented it this way.
Which other systems? All systems I know (POSIX, Java, .NET, Common Lisp) use UTC as a base and don't provide TAI at all.
The simple fact that UTC time is not monotonically increasing causes a whole host of difficulties.
And the simple fact that obtaining TAI from systems in use requires periodic updates of the leap second table causes other difficulties. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/

On 2005 February 10 Thursday 06:36, Ashley Yakeley wrote:
I see a calendar as something that maps UTCTime to other structures. UTCTime should have a distinctive place in the library, because it covers a broad range of time scales and is almost supported by OSes. But it's as much a calendar as any other structure. A calendar is a system that handles arithmetic on days and/or years and related time periods. IMO, since 1960 or so when the second became divorced from the year, seconds could also be considered a calendar property.
From this point of view, mapping to and from UTCTime is a conversion between calendars.

At 03:24 09/02/05 -0800, Ashley Yakeley wrote:
System.Time.Calendar (largely undiscussed so far):
* time zones
* getting the locale time zone
* converting times to Gregorian "calendrical" format
* calendrical arithmetic e.g. one month after March 31st
* possibly "incomplete dates" e.g. "May 1" for all years
* parsing and showing dates and times
Hmmm... I would be inclined to separate basic calendrical calulations from timezones (as opposed to timezone offsets). Prior to RFC3339, work in this area was bogged down in the comlexities of timezones... it was by separating them that we were able to come to consensus on the basics required for timestamping. #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

In article <5.1.0.14.2.20050210150449.0208fd50@127.0.0.1>,
Graham Klyne
Hmmm... I would be inclined to separate basic calendrical calulations from timezones (as opposed to timezone offsets). Prior to RFC3339, work in this area was bogged down in the comlexities of timezones... it was by separating them that we were able to come to consensus on the basics required for timestamping.
The most obvious functions in Calendar are going to be these: utcToCalendar :: TimeZone -> UTCTime -> CalendarTime calendarToUTC :: TimeZone -> CalendarTime -> UTCTime But by TimeZone I mean a fixed offset to UTC, so perhaps TimeOffset is a better name. -- Ashley Yakeley, Seattle WA

At 00:26 11/02/05 -0800, Ashley Yakeley wrote:
But by TimeZone I mean a fixed offset to UTC, so perhaps TimeOffset is a better name.
Yes, something like that. (Maybe TimeZoneOffset?) #g -- Apropos nothing in particular, I'm reminded of another wrinkle with leap seconds: it's only in the 'Z' timezone that the leap second is inserted/removed at about 23:59:59. In other timezones it occurs at the appropriate offset from this time, so they happen all around the world in synchrony, avoiding strange variations between timezone offsets. ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact
participants (8)
-
Ashley Yakeley
-
Graham Klyne
-
Gregory Wright
-
Keean Schupke
-
Ketil Malde
-
Marcin 'Qrczak' Kowalczyk
-
Scott Turner
-
Seth Kurtzberg