
Sorry for the hiatus, my job has left less free time to work on this. Please take a look at a first attempt at writing a replacement for the standard time library. http://semantic.org/TimeLib/ Take a look at the Haddock documentation: http://semantic.org/TimeLib/doc/html/ Download the source: http://semantic.org/TimeLib/TimeLib-0.1.tar.gz Or keep up-to-date: darcs get http://semantic.org/TimeLib/TimeLib/ It needs GHC 6.4. Just run "make" to build the library, tests and documentation. There's also a cabal file (as a completely separate build process), but I've been having trouble with that on Mac OS X. I'm particularly interested in comments from people who try to write little applications for it. What did you have trouble with? What made no sense? Some points: 1. There is no leap second table provided, though there is a type (LeapSecondTable) for such things. Any software compiled with a fixed table would soon become out of date. 2. There is no table of time-zones provided, since these also change. However, if there's a good way of getting this from the TZ database on the machine, I'll add that. It is actually possible to get the local time-zone for any given time, indeed one of the test programs finds your local summertime transitions. The Timezone type includes name, minutes of offset, and a "summertime" flag. 3. I allow multiple calendars with the DayEncoding class. GregorianDay is the most obvious instance, but there are some other useful ones such as ISOWeek. And anyone interested in local cultural calendars can plug their own in here. 4. The TimeLocale type comes from the already existing System.Locale. 5. I've tried to balance simplicity and functionality. Of course, the majority of people will only be interested in ordinary Gregorian date and time, so I have a simple CalendarTime type synonym with associated functions: http://semantic.org/TimeLib/doc/html/System.Time.Calendar.html#8 6. It's not possible to expunge POSIX time. I've hidden it, but it's used behind the scenes. Why? Because it's the only way to do sensible arithmetic on UTC times without knowing the leap second table and without worrying about one-second offsets. 7. I include Data.Fixed which provides a fixed-point arithmetic type (wrapper around Integer). It probably should be in a separate package. It allows dealing with seconds as a single thing, rather than as an integer/picoseconds pair. 8. I don't have any text-parsing functionality. This is a fair amount of work, so it would be good to know sensible requirements. -- Ashley Yakeley, Seattle WA

Ashley Yakeley
Please take a look at a first attempt at writing a replacement for the standard time library. http://semantic.org/TimeLib/
The general structure of the library looked quite nice. There seems to be no portable way of getting the timezone information but many applications will need a list of timezones. In this case it seems that offering something is better than nothing. Also having something like strftime available would be handy. - Einar Karttunen

In article <87acl1bn5b.fsf@yui.aoinet>,
Einar Karttunen
Ashley Yakeley
writes: Please take a look at a first attempt at writing a replacement for the standard time library. http://semantic.org/TimeLib/
The general structure of the library looked quite nice.
There seems to be no portable way of getting the timezone information but many applications will need a list of timezones. In this case it seems that offering something is better than nothing.
Also having something like strftime available would be handy.
- Einar Karttunen
Thanks. formatTime should work as strftime, though I haven't documented all the %-codes. It's written in Haskell, though I test it thoroughly against strftime. -- Ashley Yakeley, Seattle WA

Ashley Yakeley
Please take a look at a first attempt at writing a replacement for the standard time library. http://semantic.org/TimeLib/
Is midnight 00:00 or 24:00?
I think that pretending to support UT1 and TAI on most computers is too
much of a fiction to be justifiable in a library of this kind. The vast
majority of programs don't need absolute time to sub-second accuracy, and
the vast majority of operating systems can't even support UTC leap seconds
correctly. Time specialists do need this stuff, but they'll have their own
code.
Tony.
--
f.a.n.finch

In article
Is midnight 00:00 or 24:00?
Midnight is just midnight. The formatTime function will show it as "00:00".
I think that pretending to support UT1 and TAI on most computers is too much of a fiction to be justifiable in a library of this kind. The vast majority of programs don't need absolute time to sub-second accuracy, and the vast majority of operating systems can't even support UTC leap seconds correctly. Time specialists do need this stuff, but they'll have their own code.
TAI and leap-seconds are all in System.Time.TAI, so you don't have to worry about it. UT1 is necessary for historical time, since back-extending UTC is pointless and back-extending TAI completely hopeless. The UT1 type is really simple (ModJulianDate, a synonym for Rational that counts days), so there's not much extra complication. -- Ashley Yakeley, Seattle WA

On Wed, 6 Jul 2005, Ashley Yakeley wrote:
Tony Finch
wrote: Is midnight 00:00 or 24:00?
Midnight is just midnight. The formatTime function will show it as "00:00".
You miss my point that "midnight" is ambiguous, which is why ISO 8601 allows two representations of it, for the start and the end of the day.
UT1 is necessary for historical time, since back-extending UTC is pointless and back-extending TAI completely hopeless. The UT1 type is really simple (ModJulianDate, a synonym for Rational that counts days), so there's not much extra complication.
It seems that the standard astronomical time scale is TT which is based on
extending TAI, so it's very arguable whether you should use UT1 for
historical time. If you are concerned about proper support for different
time scales you should have a more comprehensive selection of conversion
functions and tables, such as historical values of delta-T for converting
between TT and UT1, etc. Of course your software will become obsolete when
the IAU/IERS/etc. change the basis of their time scales, which happens
quite frequently.
Tony.
--
f.a.n.finch

In article
On Wed, 6 Jul 2005, Ashley Yakeley wrote:
Tony Finch
wrote: Is midnight 00:00 or 24:00?
Midnight is just midnight. The formatTime function will show it as "00:00".
You miss my point that "midnight" is ambiguous, which is why ISO 8601 allows two representations of it, for the start and the end of the day.
A DateAndTime which is midnight will canonically have the TimeOfDay as 00:00:00. I don't yet have normalisation functions.
UT1 is necessary for historical time, since back-extending UTC is pointless and back-extending TAI completely hopeless. The UT1 type is really simple (ModJulianDate, a synonym for Rational that counts days), so there's not much extra complication.
It seems that the standard astronomical time scale is TT which is based on extending TAI, so it's very arguable whether you should use UT1 for historical time.
I mean "events in history", which are effectively known as approximations to UT1 (or actually, local mean time).
If you are concerned about proper support for different time scales you should have a more comprehensive selection of conversion functions and tables, such as historical values of delta-T for converting between TT and UT1, etc.
I could have a limited amount of data for the earth's rotational history, but it would be bulky and useless for any time after the compilation time of the program. And without a known application, it's not clear how much accuracy would be appropriate. -- Ashley Yakeley, Seattle WA

On Tue, Jul 05, 2005 at 01:23:12AM -0700, Ashley Yakeley wrote:
Please take a look at a first attempt at writing a replacement for the standard time library. http://semantic.org/TimeLib/
Some nits: - the DayEncoding and FormatTime instances for ModJulianDay (a synonym for Integer) aren't Haskell 98. - to make it build with Hugs, add {-# CFILES timestuff.c #-} to System/Time/Calendar/Timezone.hs and Include-Dirs: . to TimeLib.cabal. - some modules are exposed but hidden from Haddock. - the docs should say DiffTime and UTCDiffTime are in seconds. It might be useful to put the day-only stuff (ModJulianDay, DayEncoding, YearDay, GregorianDay, ISOWeek, isLeapYear, mondayStartWeek and sundayStartWeek) in a separate module.

In article <20050705161044.GA14040@soi.city.ac.uk>,
Ross Paterson
Some nits: - the DayEncoding and FormatTime instances for ModJulianDay (a synonym for Integer) aren't Haskell 98.
What's the 98 rule on this? GHC with extensions off doesn't seem to mind.
- to make it build with Hugs, add {-# CFILES timestuff.c #-} to System/Time/Calendar/Timezone.hs and Include-Dirs: . to TimeLib.cabal.
added to TODO list
- some modules are exposed but hidden from Haddock.
How do I hide modules?
- the docs should say DiffTime and UTCDiffTime are in seconds.
added to TODO list
It might be useful to put the day-only stuff (ModJulianDay, DayEncoding, YearDay, GregorianDay, ISOWeek, isLeapYear, mondayStartWeek and sundayStartWeek) in a separate module.
The original plan was to stick to just three modules, but I tend to agree that splitting Calendar as you say would be an improvement. Any objections? Also I may rename ISOWeek to ISOWeekDay. Thanks! -- Ashley Yakeley, Seattle WA

It needs a getTAItime :: IO AbsoluteTime and a getLeapSecondTable :: IO LeapSecondTable Many systems have ways to get at these and it would be a travesty if we didn't fix this hole in the API when we have the chance. As always, the library should make its best effort to get at this info. which on POSIX systems might be converting from UTCtime. but on other systems, TAItime might be the accurate one and UTCtime will have to be aproximated from it. (or on systems with up-to-date leap second tables they can both be accurate). Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs. There could be apps that will have to look at which years the leap seconds actually occured in and probing the function with every possible value in its domain is not very fun. Also, shouldn't AbsoluteTime be an instance of several Num classes? What units does DiffTime have? is it relative, or is the length of a DiffTime independent of what you do to it? John -- John Meacham - ⑆repetae.net⑆john⑈

This library looks complicated. I think some tutorial documentation about
how to implement the following use cases would be very helpful to people
that don't really care about leap seconds, etc.
Also, I see references to POXIS and Unix in System.Time.Calendar. What is
the portability of this module? Will it be implemented for Windows?
Use cases (primarily taken from real-world corporate IT applications I have
developed) :
* What is the equivalent (or closest aproximation) of the SQL DateTime type
(date and time without any timezone information)? What is the equivalent of
the SQL Date type (date without any timezone information)?
* The user enters a date as "7/4/2005." How do I determine if this date is
before or after July 1st of this year?
* How do I present the date "July 1st of this year" to the user in M/D/YYYY
format?
* How do I truncate a datetime to midnight of the same day? How do I
truncate a date to the first of the month? How do I truncate a date to the
first day of the year it occurred in?
* Given a date X, how do I find the last day of the month that X occurs in.
For example, If X is July 4th, 2005, then I want the result to be July 31st,
2005. If X is Februrary 5, then I want the result to be Februrary 28 for
non-leap-years and February 29 for leap years.
* The user enters a time T with no date, e.g. "17:30". How do I merge this
time onto a date D (e.g. July 4, 2005), so that the result has is a datetime
with date D and the time T (July 4, 2005 at 17:30).
* Given two datetimes T1, T2, how do I determine if they are on the same
date?
- Brian
On 7/5/05, John Meacham
It needs a getTAItime :: IO AbsoluteTime and a getLeapSecondTable :: IO LeapSecondTable
Many systems have ways to get at these and it would be a travesty if we didn't fix this hole in the API when we have the chance. As always, the library should make its best effort to get at this info. which on POSIX systems might be converting from UTCtime. but on other systems, TAItime might be the accurate one and UTCtime will have to be aproximated from it. (or on systems with up-to-date leap second tables they can both be accurate).
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs. There could be apps that will have to look at which years the leap seconds actually occured in and probing the function with every possible value in its domain is not very fun.
Also, shouldn't AbsoluteTime be an instance of several Num classes?
What units does DiffTime have? is it relative, or is the length of a DiffTime independent of what you do to it?
John -- John Meacham - ⑆repetae.net⑆john⑈ _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

In article
This library looks complicated. I think some tutorial documentation about how to implement the following use cases would be very helpful to people that don't really care about leap seconds, etc.
Also, I see references to POXIS and Unix in System.Time.Calendar. What is the portability of this module? Will it be implemented for Windows?
It needs only localtime_r and gettimeofday, everything else is Haskell. If those exist on Windows, or can be created, then yes. ISSUE: Will the dependence on localtime_r be a problem for older systems?
Use cases (primarily taken from real-world corporate IT applications I have developed) :
* What is the equivalent (or closest aproximation) of the SQL DateTime type (date and time without any timezone information)? What is the equivalent of the SQL Date type (date without any timezone information)?
SQL DateTime: DayAndTime GregorianDay ISSUE: Should I make a type synonym for this? I'd call it "GregorianDayAndTime". SQL Date: GregorianDay Neither include timezone.
* The user enters a date as "7/4/2005." How do I determine if this date is before or after July 1st of this year?
TODO: Parsing
* How do I present the date "July 1st of this year" to the user in M/D/YYYY format?
do now <- getCalendarTime let thisYear = ctYear now let day = GregorianDay thisYear 7 1 return (formatTime defaultTimeLocale "%m/%d/%Y" day) This actually gives "07/01/2005" rather than "7/1/2005". ISSUE: Should I make additional %-codes for this?
* How do I truncate a datetime to midnight of the same day?
datetime{dtTime = midnight}
How do I truncate a date to the first of the month?
date{gregDay = 1}
How do I truncate a date to the first day of the year it occurred in?
date{gregMonth = 1,gregDay = 1}
* Given a date X, how do I find the last day of the month that X occurs in. For example, If X is July 4th, 2005, then I want the result to be July 31st, 2005. If X is Februrary 5, then I want the result to be Februrary 28 for non-leap-years and February 29 for leap years.
This one's ugly: lastOfTheMonth (GregorianDay y m _) = let m' = (m % 12) + 1 y' = if m == 12 then y + 1 else y day = (GregorianDay y' m' 1) in encodeDay ((decodeDay day) - 1) ISSUE: What kind of "Gregorian arithmetic" should I add, if any?
* The user enters a time T with no date, e.g. "17:30". How do I merge this time onto a date D (e.g. July 4, 2005), so that the result has is a datetime with date D and the time T (July 4, 2005 at 17:30).
DayAndTime d t
* Given two datetimes T1, T2, how do I determine if they are on the same date?
dtDay t1 == dtDay t2 Thanks, these are really good. -- Ashley Yakeley, Seattle WA

In article <20050705230703.GA26379@momenergy.repetae.net>,
John Meacham
It needs a getTAItime :: IO AbsoluteTime and a getLeapSecondTable :: IO LeapSecondTable
Many systems have ways to get at these and it would be a travesty if we didn't fix this hole in the API when we have the chance. As always, the library should make its best effort to get at this info. ...
How do I implement these?
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs. There could be apps that will have to look at which years the leap seconds actually occured in and probing the function with every possible value in its domain is not very fun.
That's a good question. I used a function because that's the "least" type necessary to do the conversions, at the same time allowing estimates extending infinitely into the future (and past, if we want "proleptic UTC"). A list of pairs would have to be walked through, in effect converted to the function type.
Also, shouldn't AbsoluteTime be an instance of several Num classes?
No, I don't think any Num functions apply. There's no "zero time" and you can't meaningfully add 3am today to 7pm tomorrow.
What units does DiffTime have?
Seconds, and I'll add that to the doc.
is it relative, or is the length of a DiffTime independent of what you do to it?
A DiffTime is always real absolute seconds such as a good clock might measure, independent of whatever the earth might be doing. -- Ashley Yakeley, Seattle WA

On Wed, Jul 06, 2005 at 01:38:12AM -0700, Ashley Yakeley wrote:
In article <20050705230703.GA26379@momenergy.repetae.net>, John Meacham
wrote: It needs a getTAItime :: IO AbsoluteTime and a getLeapSecondTable :: IO LeapSecondTable
Many systems have ways to get at these and it would be a travesty if we didn't fix this hole in the API when we have the chance. As always, the library should make its best effort to get at this info. ...
How do I implement these?
I was thinking for the initial implementation getTAITime = do lst <- getLeapSecondTable t <- getCurrentTime return (utcToTAITime lst t) getLeapSecondTable = do -- check for /etc/leapseconds.txt -- return contents of file if it exists -- else, return built in table. This will make it very straightforward for anyone to get accurate TAI times by adding a one-liner to their crontab to grab the leapsecondtable from NIST at least once every few months. Of course, getLeapSecondTable and getTAITime will be modified to use any local interfaces available or when POSIX eventually specifies some TAI interface functions.
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs. There could be apps that will have to look at which years the leap seconds actually occured in and probing the function with every possible value in its domain is not very fun.
That's a good question. I used a function because that's the "least" type necessary to do the conversions, at the same time allowing estimates extending infinitely into the future (and past, if we want "proleptic UTC"). A list of pairs would have to be walked through, in effect converted to the function type.
Also, shouldn't AbsoluteTime be an instance of several Num classes?
No, I don't think any Num functions apply. There's no "zero time" and you can't meaningfully add 3am today to 7pm tomorrow.
But the beauty of TAI is that interval and absolute times are on the same scale. I would argue that it is the one type where arithmetic actually makes sense. you can subtract two dates and get an absolute measure of the time difference between them. or add two dates and get the sum of their offsets from 1970. (there is a zero time, the TAI epoch). Even division and multiplication make sense (but the dimensionalities are a little more iffy with them, so I'd convert to integers first, however the math is sound). For TAI, you don't need separate Difference and Absolute types because in essence, all TAI values are offsets, with an implied endpoint at 1970-1-1 0:0:0. John -- John Meacham - ⑆repetae.net⑆john⑈

In article <20050706220345.GE26379@momenergy.repetae.net>,
John Meacham
I was thinking for the initial implementation
getTAITime = do lst <- getLeapSecondTable t <- getCurrentTime return (utcToTAITime lst t)
The problem with this is that it will re-fetch the leap-second table with every call, at the very least, re-examining the file to see whether it's changed.
getLeapSecondTable = do -- check for /etc/leapseconds.txt -- return contents of file if it exists -- else, return built in table.
Returning a built-in table is worse than useless, as any program compiled with it will soon break. We could however check for /etc/leapseconds.txt, that might be useful. But it's not clear what the behaviour on Windows or other platforms should be. What I'd really like to see is an established cross-platform convention for providing leap-second tables, and then we could interface to that. What I am tempted to do is something like this: readLeapSecondTable :: FilePath -> IO LeapSecondTable
Of course, getLeapSecondTable and getTAITime will be modified to use any local interfaces available or when POSIX eventually specifies some TAI interface functions.
What do you mean by "modified to use any local interfaces available"? Certainly if POSIX does some work here we can provide functions then. -- Ashley Yakeley, Seattle WA

Ashley Yakeley
getLeapSecondTable = do [....]
Returning a built-in table is worse than useless, as any program compiled with it will soon break.
Apparently, that's what the Perl library (libdatetime-leapsecond-perl) does. (It's the only thing I can find on my box that seems to worry about leap seconds) "break" as in "give slightly inaccurate results".
We could however check for /etc/leapseconds.txt, that might be useful. But it's not clear what the behaviour on Windows or other platforms should be.
Is /etc/leapseconds.txt a standardized file/location at all?
readLeapSecondTable :: FilePath -> IO LeapSecondTable
It would be nice if it had the ability to fetch the table over the net as well, perhaps? -k -- If I haven't seen further, it is by standing in the footprints of giants

In article <87zmszqafq.fsf@sefirot.ii.uib.no>,
Ketil Malde
Returning a built-in table is worse than useless, as any program compiled with it will soon break.
Apparently, that's what the Perl library (libdatetime-leapsecond-perl) does. (It's the only thing I can find on my box that seems to worry about leap seconds)
"break" as in "give slightly inaccurate results".
Well, if you don't mind being off by a second or two, then you don't need leap-seconds at all. Otherwise the program you compiled in 2005 will be wrong in 2010.
We could however check for /etc/leapseconds.txt, that might be useful. But it's not clear what the behaviour on Windows or other platforms should be.
Is /etc/leapseconds.txt a standardized file/location at all?
I don't even know if it is.
readLeapSecondTable :: FilePath -> IO LeapSecondTable
It would be nice if it had the ability to fetch the table over the net as well, perhaps?
We should at least also (or instead) have parseLeapSecondTable :: String -> Maybe LeapSecondTable This would parse "leap.sec" files as provided by USNO (unless there's some other standard format). -- Ashley Yakeley, Seattle WA

On 2005-07-06, John Meacham
But the beauty of TAI is that interval and absolute times are on the same scale.
True, but so what?
I would argue that it is the one type where arithmetic actually makes sense. you can subtract two dates and get an absolute measure of the time difference between them.
Check.
or add two dates and get the sum of their offsets from 1970. (there is a zero time, the TAI epoch).
Never useful. The type system should be used to prevent it.
Even division and multiplication make sense (but the dimensionalities are a little more iffy with them, so I'd convert to integers first, however the math is sound).
The conversion to integers should be explicit.
For TAI, you don't need separate Difference and Absolute types because in essence, all TAI values are offsets, with an implied endpoint at 1970-1-1 0:0:0.
False, and true. This is essentially the different between an affine space and a vector space -- an affine space, such as points are a torsor for the corresponding vector space of durations. The numeric classes need to be more fine grained. -- Aaron Denney -><-

In article
The numeric classes need to be more fine grained.
Yes! I've been bashing my head against the "Num" class when what I really have is an affine space. Really, it just doesn't make any sense to add two absolute times together to get another absolute time. And trying to multiply times together to get a time is even more ridiculous. -- Ashley Yakeley, Seattle WA

On Tue, 19 Jul 2005, Ashley Yakeley wrote:
In article
, Aaron Denney wrote: The numeric classes need to be more fine grained.
Yes! I've been bashing my head against the "Num" class when what I really have is an affine space.
Really, it just doesn't make any sense to add two absolute times together to get another absolute time. And trying to multiply times together to get a time is even more ridiculous.
The NumericPrelude class hierarchy tries to resolve such problems. Although a class for affine spaces is not yet contained it provides separation of multiplication from addition. http://cvs.haskell.org/darcs/numericprelude/

On Wed, Jul 06, 2005 at 01:38:12AM -0700, Ashley Yakeley wrote:
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs. There could be apps that will have to look at which years the leap seconds actually occured in and probing the function with every possible value in its domain is not very fun.
That's a good question. I used a function because that's the "least" type necessary to do the conversions, at the same time allowing estimates extending infinitely into the future (and past, if we want "proleptic UTC"). A list of pairs would have to be walked through, in effect converted to the function type.
How about making LeapSecondTable an abstract type and having functions for converting to and from a list based representation? then it could use whatever efficient representation it wants internally and we still have the ability to get at or provide the raw data. However, you raise a good point about implementations that 'estimate' infinitly far into the future or the past, not sure what to do about those. John -- John Meacham - ⑆repetae.net⑆john⑈

On Tue, 5 Jul 2005, John Meacham wrote:
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs.
That's not sufficient, because leap seconds may (currently) occur at two
points during the year. If you are interested in accurate absolute time
over history, then it is also insufficient because before 1972 the offset
between UTC and TAI was continuously variable, and in the future the rules
for UTC are likely to change.
Tony.
--
f.a.n.finch

On Wed, Jul 06, 2005 at 11:40:31AM +0100, Tony Finch wrote:
On Tue, 5 Jul 2005, John Meacham wrote:
Also, it would be nice if the LeapSecondTable was not a functional type, but rather something with structure, like a list of (year,offset) pairs.
That's not sufficient, because leap seconds may (currently) occur at two points during the year. If you are interested in accurate absolute time over history, then it is also insufficient because before 1972 the offset between UTC and TAI was continuously variable, and in the future the rules for UTC are likely to change.
Yeah, which is why we need a good TAI type. TAI is defined infinitly far into the past and future. while UTC disapears before 1972 and we can't know what intervals future UTC times represent. It was declared that leap seconds will only occur at the end of years from now on, rather than possibly every 6 months. but I wouldn't be opposed to a more general format since they might charge the rules again (although that seems unlikely). John -- John Meacham - ⑆repetae.net⑆john⑈
participants (9)
-
Aaron Denney
-
Ashley Yakeley
-
Brian Smith
-
Einar Karttunen
-
Henning Thielemann
-
John Meacham
-
Ketil Malde
-
Ross Paterson
-
Tony Finch