Re: time since the epoch
Dear Juanma, thanks for your remarks. Juanma Barranquero (Mon, Nov 10, 2003 at 10:54:22AM +0100): On Fri, 7 Nov 2003 19:55:47 +0100 Stefan Karrmann [EMAIL PROTECTED] wrote: I've inserted 'convert = (uncurry cFromTai) . cToTai'. Great, thanks. A fixed and checked version is appended and carbon copied to [EMAIL PROTECTED]. What's haskell-libs-developers? I thought libraries' development was carried over on [EMAIL PROTECTED] (And shouldn't we be discussing Tai.lhs there, BTW :) Well, the original thread was on this list. I'm moving it to [EMAIL PROTECTED] now. I'm attaching a patch (diff -u2) with a few small changes: I've included it. More coments: - I'm sending you the patch throw the Haskell list because previous attempts of sending to your e-mail address failed. I'm using ASK as a spam killer. Do you have problems with it? - Are you very fond of the literate style? I ask because unlit'ing it would allow adding Haddock coments, which would be nice. I've given it a try, but my comment marking could be improved. - I'm not sure I like depending on a leapseconds table hardcoded in the source, even if it changes slowly. Wouldn't it be better to have the data in a file and load it through unsafePerformIO? (And isn't loading configuration data one of the few good examples of use of unsafePerformIO, after all? :) Well, I included the two as examples. The empty one is correct for all times before 1970-01-01. That's more than ten billion years. - I get a warning with -Wall: Warning: Defined but not used: TimeDiff, days_from_MJD2unixEpoch, days_from_unixEpoch2MJD', hours_per_day, isodelta, isomoveDHM, isomoveS, isomoveYM, libtaiEpoch, month_per_year, test, test2 Some values are only for testing and debugging while others are experimental, e.g. TimeDiff and friends. Several of these are neither used nor exported. ??? Regards, -- Stefan Karrmann Bitte bzip2 benutzen! ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
On Fri, 7 Nov 2003 19:55:47 +0100 Stefan Karrmann [EMAIL PROTECTED] wrote: I've inserted 'convert = (uncurry cFromTai) . cToTai'. Great, thanks. A fixed and checked version is appended and carbon copied to [EMAIL PROTECTED]. What's haskell-libs-developers? I thought libraries' development was carried over on [EMAIL PROTECTED] (And shouldn't we be discussing Tai.lhs there, BTW :) I'm attaching a patch (diff -u2) with a few small changes: - 1%seconds_per_day - 1 % seconds_per_day (otherwise GHC complains in -fglasgow-exts mode because it misinterprets it as an implicit parameter). - I've put a few _ here and there to silence warnings for unused arguments. - I've renamed a few variables because of shadows an existing binding warnings. - I've deleted a few internal definitions apparently not used (according to -Wall), like cumulated_month_length_after_february. - I've corrected a few typos. More coments: - I'm sending you the patch throw the Haskell list because previous attempts of sending to your e-mail address failed. - Are you very fond of the literate style? I ask because unlit'ing it would allow adding Haddock coments, which would be nice. - I'm not sure I like depending on a leapseconds table hardcoded in the source, even if it changes slowly. Wouldn't it be better to have the data in a file and load it through unsafePerformIO? (And isn't loading configuration data one of the few good examples of use of unsafePerformIO, after all? :) - I get a warning with -Wall: Warning: Defined but not used: TimeDiff, days_from_MJD2unixEpoch, days_from_unixEpoch2MJD', hours_per_day, isodelta, isomoveDHM, isomoveS, isomoveYM, libtaiEpoch, month_per_year, test, test2 Several of these are neither used nor exported. ??? Thanks, Juanma Tai.lhs.diff.bz2 Description: Binary data ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Dear Juanma, some last moment changes broke the library, I am sorry. Juanma Barranquero (Thu, Nov 06, 2003 at 05:03:03PM +0100): On Sat, 1 Nov 2003 17:36:11 +0100 Stefan Karrmann [EMAIL PROTECTED] wrote: a while ago time calculation was subject on this list. Now, I have a time library based on the TAI (international atomic time) time scale. I get the following error with GHCi: Compiling Main ( Tai.lhs, interpreted ) Tai.lhs:450: Couldn't match `LeapSeconds' against `TAI' Also, wouldn't make sense to add: cConvert :: (Calendar a, Calendar b) = a - b cConvert = cFromTai . cToTai I've inserted 'convert = (uncurry cFromTai) . cToTai'. A fixed and checked version is appended and carbon copied to [EMAIL PROTECTED]. Regards, -- Stefan Karrmann Tai.lhs.bz2 Description: Binary data ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
On Sat, 1 Nov 2003 17:36:11 +0100 Stefan Karrmann [EMAIL PROTECTED] wrote: a while ago time calculation was subject on this list. Now, I have a time library based on the TAI (international atomic time) time scale. I get the following error with GHCi: Compiling Main ( Tai.lhs, interpreted ) Tai.lhs:450: Couldn't match `LeapSeconds' against `TAI' Expected type: LeapSeconds Inferred type: TAI In the first argument of `cFromTai', namely `taileap1' In the first argument of `cSecond', namely `(cFromTai taileap1 lst)' Tai.lhs:453: Couldn't match `LeapSeconds' against `TAI' Expected type: LeapSeconds Inferred type: TAI In the first argument of `cFromTai', namely `taileap2' In the first argument of `cSecond', namely `(cFromTai taileap2 lst)' Tai.lhs:472: Couldn't match `LeapSeconds' against `TAI' Expected type: LeapSeconds Inferred type: TAI In the first argument of `cFromTai', namely `taileap1' In the first argument of `cSecond', namely `(cFromTai taileap1 lst)' Tai.lhs:475: Couldn't match `LeapSeconds' against `TAI' Expected type: LeapSeconds Inferred type: TAI In the first argument of `cFromTai', namely `taileap2' In the first argument of `cSecond', namely `(cFromTai taileap2 lst)' Failed, modules loaded: none. Also, wouldn't make sense to add: cConvert :: (Calendar a, Calendar b) = a - b cConvert = cFromTai . cToTai Or it is already there and I've missed it? Juanma ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Stefan Karrmann [EMAIL PROTECTED] writes: a while ago time calculation was subject on this list. Now, I have a time library based on the TAI (international atomic time) time scale. This is cool! But what actually happens when people post interesting library code to the list? Does somebody snarf it, and put it in a more convenient place? Why not upload it into the Haskell library site at Sourceforge, and just post a description and a pointer? http://sourceforge.net/projects/haskell-libs/ -kzm -- If I haven't seen further, it is by standing in the footprints of giants ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Hi, a while ago time calculation was subject on this list. Now, I have a time library based on the TAI (international atomic time) time scale. Peter Thiemann (Thu, Feb 06, 2003 at 12:40:14PM -0800): John's code illustrates TimeDiff's deficiencies perfectly: There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. newtype TimeDiff = TimeDiff Rational deriving (Eq, Ord) Hmm, this is underspecified! As another poster said, (pointing out http://cr.yp.to/libtai, but it is better to look at http://cr.yp.to/time.html, which has a discussion on UTC vs TAI vs UNIX time) the official source of time is TAI, so it is best to base a time library *on the number of TAI seconds since a reference date* (which is btw what the libtai is all about). For compatibility with UNIX time, Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI [http://cr.yp.to/proto/utctai.html]. So this mostly means that you need to set your system clock correctly:-) Sincerly, -- Stefan Karrmann 2003 Copyright (C) Stefan Karrmann [EMAIL PROTECTED] All rights reserved. The rights of the GNU Library General Public Licence Version 2 are granted, for details confer http://www.fsf.org/copyleft/lgpl.html. This module provides data structures and functions to calculate with Temps Atomique International (International Atomic Time, short TAI). For further information about time see, e.g. http://www.boulder.nist.gov/timefreq/general/glossary3.htm. module Main ( --main, TAI(TAI) -- Temps atomique international ,TAIDiff(TAIDiff) ,taidelta -- TAI - TAI - TAIDiff ,taimove -- TAI - TAIDiff - TAI ,taiadd-- TAIDiff - TAIDiff - TAIDiff ,taisub-- TAIDiff - TAIDiff - TAIDiff ,taimult -- Rational - TAIDiff - TAIDiff ,taipow-- Integer - TAIDiff - TAIDiff ,tainegate -- TAIDiff - TAIDiff ,tairecip -- TAIDiff - TAIDiff ,unixEpoch -- TAI ,LeapSeconds(LeapSeconds) ,emptyLeaps-- LeapSeconds table valid until ISO 1970-01-01 ,leaps_2002_06_01 -- LeapSeconds table valid until ISO 2002-06-01 ,UTC(UTC) ,tai2utc -- LeapSeconds - TAI - UTC ,utc2tai -- UTC - TAI ,MJD(MJD) -- Modified Julian Date ,utc2mjd -- UTC - MJD ,mjd2utc -- MJD - UTC ,JD(JD)-- Julian Date ,mjd2jd-- MJD - JD ,jd2mjd-- JD - MJD ,ISO ,mjd2iso -- MJD - ISO ,iso2mjd -- ISO - MJD ) where import Prelude import List import Ratio Values of TAIDiff contains (fractional) seconds without a reference point. newtype TAIDiff = TAIDiff Rational deriving (Eq,Ord,Show,Read) This belongs almost to the class Num, but multiplication does not make sense - you would get square seconds. Thus, we have to define our own functions until class (UnitRing r, Group a) = Modul a enters Haskell. taidelta (TAI r1) (TAI r2) = TAIDiff (r1 - r2) taimove (TAI r1) (TAIDiff r2) = TAI (r1 + r2) taiadd (TAIDiff r1) (TAIDiff r2) = TAIDiff (r1 + r2) taisub (TAIDiff r1) (TAIDiff r2) = TAIDiff (r1 - r2) taimult r1 (TAIDiff r2) = TAIDiff (r1 * r2) taipow i (TAIDiff r) = TAIDiff (r ^^ i) tainegate (TAIDiff r) = TAIDiff (- r) tairecip (TAIDiff r) = TAIDiff (1/r) Values of TAI are fixed points on the time axis of the eigentime of the standardisation organisation in our space-time universe. newtype TAI = TAI Rational deriving (Eq,Ord,Show,Read) untai (TAI r) = r The first defined TAI value - UNIX(TM) epoch, i.e. Thursday ISO 1970-01-01T00:00:00 unixEpoch = TAI 10 -- == ISO 1970 01 01 0 0 0 emptyLeaps libtaiEpoch = 4611686018427387914 -- 2^62 + 10 The leap second table data structure data LeapSeconds = LeapSeconds TAI{- valid until -} [(TAI, {- when -} Bool {- It is additional. -} )] deriving (Eq,Show,Read) Valid leap second table for all times before unix epoch. emptyLeaps = LeapSeconds unixEpoch [] Up to date leap seconds can be found at some official sources: http://maia.usno.navy.mil/leapsec.html http://hpiers.obspm.fr/webiers/general/earthor/utc/UTC.html leaps_2002_06_01 = let valid = utc2tai $ mjd2utc $ iso2mjd $ ISO 2002 06 01 23 59 59 lst lst@(LeapSeconds _ ls) = h 1998 12 31 True $ h 1997 06 30 True $ h 1995 12 31 True $ h 1994 06 30 True $ h 1993 06 30 True $ h 1992 06 30 True $ h 1990 12 31 True $ h 1989 12 31 True $ h 1987 12 31 True $ h 1985 06 30 True $ h 1983 06 30 True $ h 1982 06 30 True $ h 1981 06 30 True $ h 1979 12 31 True
[OT] Re: time since the epoch
Peter Thiemann (Mon, Feb 10, 2003 at 04:36:17PM -0800): Stefan == Stefan Karrmann [EMAIL PROTECTED] writes: Stefan Peter Thiemann (Thu, Feb 06, 2003 at 12:40:14PM -0800): John's code illustrates TimeDiff's deficiencies perfectly: There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. Stefan What time takes a year - 365 or 366 days? There are leap years! Stefan What time takes a month - 28, 29, 30 or 31 days? Stefan A week takes 7 days. Stefan How long is a day - 86399, 86400 or 86401 seconds and how long is a Stefan hour - 3599, 3600 or 3601 seconds? There are leap seconds! Stefan A second is the basic amount of time. Minutes, hours, and days (even weeks) are also well defined in terms of seconds. But not months and years. No! There are leap seconds which let some minute contain exactly 61 or 59 seconds! Thus, you have a different fixed scales. The elements of each scale are given by a FIXED number of the first element.: 1. Seconds (SI-unit), kilo seconds, etc. 2. Minute, hours, days, weaks 3. Months, years, decades, centuries, ages, etc. My conclusion is that time differences really should be measured in seconds and picoseconds. Stefan How do you measure 100 attoseconds? 1 attoseconds (1E-18 seconds) is a lot smaller then 1 picosecond. type TimeDiff = (Integer, Integer) Should (x,y) :: TimeDiff mean the fractional x/y ? If you still intend x to be seconds and y to be picoseconds you cannot represent attoseconds . Stefan More general is Stefan newtype TimeDiff = TimeDiff Rational Stefanderiving (Eq, Ord) I agree, I just was not bold enough to propose this :-) However, this seems to be close to the limit of the measurable, and I'm wondering how much precision is required in practice. Here you are right. But if your calculations takes the same precision adding rationals is cheap. Hmm, this is underspecified! As another poster said, (pointing out http://cr.yp.to/libtai, but it is better to look at http://cr.yp.to/time.html, which has a discussion on UTC vs TAI vs UNIX time) the official source of time is TAI, so it is best to base a time library *on the number of TAI seconds since a reference date* (which is btw what the libtai is all about). For compatibility with UNIX time, Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI [http://cr.yp.to/proto/utctai.html]. So this mostly means that you need to set your system clock correctly:-) Stefan No, you have to check for leap seconds. There is one in Stefan every few years. I do not understand this comment. All I am saying is that you should set your system clock to the number of seconds since the epoch. Leap seconds only come into play when converting to UTC. -- Peter Thiemann, Prof. Dr. Institut für Informatik, Universität Freiburg, Germany http://www.informatik.uni-freiburg.de/~thiemann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
On 11 Feb 2003, at 18:23, George Russell wrote: Add 1 month to 1st February 2003. This produces 1st March 2003. (with no overflow.) Here, you add 28 days, which is the number of days in (this) February. Fair enough. Add 1 month to 31st January 2003. Then we get 31st February 2003. This clearly requires an overflow; we note that February 2003 has 28 days, and so roll over to 3rd March 2003. Here, you add 31 days, which is the number of days in January. Also fair enough. Note that in this case Add 1 month is not a monotonic operation. Add 1 minute to 23:59:60 31st December 2003. I assume that this is a valid time and that it will be a leap second; if not choose some other year. This is complicated since we have multiple overflows. First stage you get the invalid time 23:60:60 31st December 2003. But **HERE**, you add 60 seconds. Why? If you want to add 1 minute to 23:59:60 31st December 2003, and assuming still that it is a leap minute, then to be consistent with the rule for months, I think you ought to add **61** seconds---the number of seconds in *this* minute. If the problem had been to add 60 seconds, I would agree, but if the problem is to add 1 minute, I think there's a flaw here. /| . . . (_|/ o n a t h a n /| (_/ ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
George So while I started typing this thinking it was a straight George choice between Peter's monotonicity/invertibility and the George fact that my system corresponds better to natural usage, George Peter doesn't even have monotonicity or invertibility. Yes, I also realized that after I left my office. Sorry for the confusion. ... Now, isn't that a good argument for just *defining* the length of a year and a month in terms of seconds and then go with it. It naturally gives you all nice properties and you cannot argue if and when you want to overflow or underflow or whatever? -Peter ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
Jonathan Coxhead wrote (quoting me, snipped) Add 1 minute to 23:59:60 31st December 2003. I assume that this is a valid time and that it will be a leap second; if not choose some other year. This is complicated since we have multiple overflows. First stage you get the invalid time 23:60:60 31st December 2003. But **HERE**, you add 60 seconds. Why? If you want to add 1 minute to 23:59:60 31st December 2003, and assuming still that it is a leap minute, then to be consistent with the rule for months, I think you ought to add **61** seconds---the number of seconds in *this* minute. If the problem had been to add 60 seconds, I would agree, but if the problem is to add 1 minute, I think there's a flaw here. Your arithmetic is faulty. Because we are assuming 23:59:60 31st December 2003 is a leap second, there are 61 seconds until 00:01:00 1st January 2004, the time my method (eventually) produces. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: time since the epoch
[snip] It is always a problem to lump things with different semantics into the same type :-) What I'm arguing is that there should be only one fixed-duration offset datatype and it should be in terms of (seconds, picoseconds). Other fixed durations can be easily defined in terms of this datatype. I'm still not sure that you actually want base-dependent offsets, but again they can be easily defined on top of the fixed duration datatype. And they should be specified separately from the base functionality. [snip] I wrote a reply, but I don't really have anything new to say over what's been said already, so I'll keep it brief instead. The copy of ISO8601 that I looked at is here: http://www.astroclark.freeserve.co.uk/iso8601/index.htm, but from what you said I'm guessing you're looking at a different version. Anyway, to sum up: - I agree that there should be a constant-duration time offset type. However, TimeDiff does actually fuction perfectly well as one at the moment, since diffClockTimes only fills in the seconds and picoseconds fields. - I believe a reasonable interpretation of the other fields of TimeDiff is as base-dependent offsets. The current implementation in GHC doesn't do this, but you can use TimeExts which does. - Our implementation of ClockTime uses C's gettimeofday(), which apparently is based a broken definition of the epoch. Oh well :-) Cheers, Simon ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
Peter wrote (snipped) As far as I read ISO8601 (which also has a notation for durations) this is unspecifed :-) And as far as I read TimeExts.lhs it does some sort of rollover. My take would be to specify the behavior for adding something like a TimeDiff to a base date in a consistent manner and then cast that in stone. If there is a (reasonable) standard for this kind of calculation, then this should be the basis for the specification. OK, what TimeExts does, I hope, is add the appropriate amount of the appropriate time unit (whatever it is) directly, then rely on the CalendarTime conversions to resolve any overflows. This probably isn't very clear, so I'll give some examples of what I think ought to happen. Add 1 month to 1st February 2003. This produces 1st March 2003. (with no overflow.) Add 1 month to 31st January 2003. Then we get 31st February 2003. This clearly requires an overflow; we note that February 2003 has 28 days, and so roll over to 3rd March 2003. Note that in this case Add 1 month is not a monotonic operation. Add 1 minute to 23:59:60 31st December 2003. I assume that this is a valid time and that it will be a leap second; if not choose some other year. This is complicated since we have multiple overflows. First stage you get the invalid time 23:60:60 31st December 2003. I don't know what TimeExts (or rather the CalendarTime conversions) do in this case, but what I think they *ought* to do is work from the most significant unit down, rolling around to produce a significant date at each time. When we roll around, we have to bump the next unit, and iterate. So: 2003 OK. 2003 December OK. 2003 December 31st OK. 2003 December 31st 23 OK. 2003 December 31st 23:60 NOT OK. We bump the next unit and subtract this one, then we have to iterate from the top down. So we replace 23:60 by 24:00. and get 2003 December 31st 24 not OK. Replaces 31st 24 by 32nd 00. 2003 December 32nd not OK 2003 Unidecimber (13th month) 1st not OK 2004 January OK 2004 January 1st OK 2004 January 1st 00 OK 2004 January 1st 00:00 OK 2004 January 1st 00:00:60 Not OK. Replace 00:60 by 01:00 and you eventually get 2004 January 1st 00:01:00 ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Stefan == Stefan Karrmann [EMAIL PROTECTED] writes: Stefan Peter Thiemann (Thu, Feb 06, 2003 at 12:40:14PM -0800): John's code illustrates TimeDiff's deficiencies perfectly: There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. Stefan What time takes a year - 365 or 366 days? There are leap years! Stefan What time takes a month - 28, 29, 30 or 31 days? Stefan A week takes 7 days. Stefan How long is a day - 86399, 86400 or 86401 seconds and how long is a Stefan hour - 3599, 3600 or 3601 seconds? There are leap seconds! Stefan A second is the basic amount of time. Minutes, hours, and days (even weeks) are also well defined in terms of seconds. But not months and years. My conclusion is that time differences really should be measured in seconds and picoseconds. Stefan How do you measure 100 attoseconds? type TimeDiff = (Integer, Integer) Stefan More general is Stefan newtype TimeDiff = TimeDiff Rational Stefanderiving (Eq, Ord) I agree, I just was not bold enough to propose this :-) However, this seems to be close to the limit of the measurable, and I'm wondering how much precision is required in practice. Hmm, this is underspecified! As another poster said, (pointing out http://cr.yp.to/libtai, but it is better to look at http://cr.yp.to/time.html, which has a discussion on UTC vs TAI vs UNIX time) the official source of time is TAI, so it is best to base a time library *on the number of TAI seconds since a reference date* (which is btw what the libtai is all about). For compatibility with UNIX time, Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI [http://cr.yp.to/proto/utctai.html]. So this mostly means that you need to set your system clock correctly:-) Stefan No, you have to check for leap seconds. There is one in Stefan every few years. I do not understand this comment. All I am saying is that you should set your system clock to the number of seconds since the epoch. Leap seconds only come into play when converting to UTC. -- Peter Thiemann, Prof. Dr. Institut für Informatik, Universität Freiburg, Germany http://www.informatik.uni-freiburg.de/~thiemann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
SM I wrote a reply, but I don't really have anything new to say over what's SM been said already, so I'll keep it brief instead. The copy of ISO8601 SM that I looked at is here: SM http://www.astroclark.freeserve.co.uk/iso8601/index.htm, but from what SM you said I'm guessing you're looking at a different version. Oops, I guess I did. However, the 2000 version does not clarify matters much more. It does, however, make the distinction between day (= 24 hours) and calendar day (period until the same daytime is reached again). Regarding, time periods it only specifies the syntax, not the semantics. Oh well. SM Anyway, to sum up: SM - I agree that there should be a constant-duration time offset type. SM However, TimeDiff does actually fuction perfectly well as one at SM the moment, since diffClockTimes only fills in the seconds and SM picoseconds fields. Ok. But there is the caveat that TimeDiff { ... tdSec :: Int ... } which will give rise to overflows in a few years. SM - I believe a reasonable interpretation of the other fields of SM TimeDiff is as base-dependent offsets. The current implementation SM in GHC doesn't do this, but you can use TimeExts which SM does. In addition, it does not muddle months, years, etc together into one TimeDiff value. This is a GOOD THING because you would have to specify the sequence in which the various items are added to the reference to get a well-defined behavior. SM - Our implementation of ClockTime uses C's gettimeofday(), which SM apparently is based a broken definition of the epoch. Oh well :-) IMHO, the TimeDiff data type is the source of all evil (in Time, at least). What about the following proposal for extending TimeExts: * Add a datatype data Duration = Duration Integer Integer * Define the operations addToClockTime :: Duration - ClockTime - ClockTime diffClockTimes :: ClockTime - ClockTime - Duration [[ and deprecate using them from Time ]] * Write an explicit specification for the remaining operators. This should not be much effort. [the overall goal being, of course, to phase out the Time module] For further cleanup, the stuff dealing with CalendarTime could be moved into its own module Calendar. And it would be very useful to have parsing functions like parseTime :: String - CalendarTime [might have to be IO CalendarTime because the interpretation depends on the local time zone, etc] Cheers -Peter ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
George OK, what TimeExts does, I hope, is add the appropriate amount of the appropriate George time unit (whatever it is) directly, then rely on the CalendarTime conversions to George resolve any overflows. This probably isn't very clear, George so I'll give some examples of what I think ought to George happen. I see. You propose to always add the duration of the current entity. IE, a month rooted in January has 31 days, and a year rooted in a leap year has 366 days. How do you define subtraction, given that your addition is not monotonic and that you (probably) want addition and subtraction be inverses? Actually, you could equally well argue that you should always take the duration of the next following entity (in seconds, but I won't go into that detail). While this means that (in a non-leap year) January 1 + 1 month = January 29 it preserves monotonicity: January 31 + 1 month = February 28 so that you could define subtraction (although at some expense). George Add 1 month to 1st February 2003. This produces 1st March 2003. (with no overflow.) George Add 1 month to 31st January 2003. Then we get 31st February 2003. This clearly requires George an overflow; we note that February 2003 has 28 days, and so roll over to 3rd March 2003. George Note that in this case Add 1 month is not a monotonic operation. George Add 1 minute to 23:59:60 31st December 2003. I assume George that this is a valid time and that it George will be a leap second; if not choose some other year. [... long calculation ...] George 2004 January 1st 00:01:00 I would argue that adding one minute might be interpreted either * as an absolute minute (add 60 seconds) * or as the duration of the next calendar minute (which happens to be 60 seconds, too). (both resulting in 00:00:59) In any case, it is merely a matter of interpreting the amount in terms of seconds, and then let the translation inside of calendartime do its work for you. -Peter ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Time since the epoch
Peter Thiemann wrote: George OK, what TimeExts does, I hope, is add the appropriate amount of the appropriate George time unit (whatever it is) directly, then rely on the CalendarTime conversions to George resolve any overflows. This probably isn't very clear, George so I'll give some examples of what I think ought to George happen. I see. You propose to always add the duration of the current entity. IE, a month rooted in January has 31 days, and a year rooted in a leap year has 366 days. How do you define subtraction, given that your addition is not monotonic and that you (probably) want addition and subtraction be inverses? I would drop the requirement that addition and subtraction be inverse, and use exactly the same procedure only with changes of sign. So first adjust the date, then roll. Actually, you could equally well argue that you should always take the duration of the next following entity (in seconds, but I won't go into that detail). While this means that (in a non-leap year) January 1 + 1 month = January 29 it preserves monotonicity: January 31 + 1 month = February 28 so that you could define subtraction (although at some expense). [snip] Well I don't see much point in arguing this at length, since this is one case where it doesn't really matter what we do so long as we do something. HOWEVER I will make some brief points and then leave it to other Haskellers to argue about. Here are some specific objections. (1) Peter's notion of addition is odd. I can't believe anyone but Peter would say that the date 1 month from 1st January is 29th January in a non-leap year, or 30th January in a leap year. (2) Peter's notion of subtraction is worse. True, it's inverse to addition, but that's all it's good for. For example, if you ask What happens if you subtract 1 month from 1st February?, then Peter's method gives you 4th January in a normal year, or 3rd January in a leap year. I can't believe if you were to ask someone on the street What date is 1 month before 1st February? they would give you that answer. (3) Both are fundamentally asymmetric. What happens for example when you add (-1) months? Do you subtract the length of the previous month? This is nice and symmetrical. Or do you subtract the length of this month? This is not symmetrical, but means that it is the same as subtracting 1 month. However there's an ever better objection which has just occurred to me. Peter's notion of subtraction is UNDEFINED. For, what is 29th January MINUS 1 month? As he says, in his system. January 1 + 1 month = January 29 but of course it is also true that December 29 + 1 month = January 29. Even worse, December 30 + 1 month = January 30th, so you don't have monotonicity either. So while I started typing this thinking it was a straight choice between Peter's monotonicity/invertibility and the fact that my system corresponds better to natural usage, Peter doesn't even have monotonicity or invertibility. So I think my method wins. Nyaaa. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
SM TimeDiff isn't a duration, it's a way of specifying time offsets whose SM duration depends on the base to which the offset is being added. If we SM only had constant-duration offsets, then there would be no way to say SM give me a ClockTime for this time next Wednesday. [nitpicking] Oops, this is not the purpose stated in the library report: The TimeDiff type records the difference between two clock times in a user-readable way. Anyway, the sort of specification that you are talking about is really a pain IMHO. Actually, you could not use TimeDiff to state it, either. [ISO8601 allows it but I think it's too imprecise to be useful] SM The problem is really that all the different kinds of offset are lumped SM into one type: there ought to be a TimeDiffSeconds, TimeDiffMonths, and SM so on. TimeDiffSeconds is a constant-duration offset, but SM TimeDiffMonths isn't. The problem with lumping them into one type is SM that if multiple components are non-zero, you don't know in which order SM to add them. It is always a problem to lump things with different semantics into the same type :-) What I'm arguing is that there should be only one fixed-duration offset datatype and it should be in terms of (seconds, picoseconds). Other fixed durations can be easily defined in terms of this datatype. I'm still not sure that you actually want base-dependent offsets, but again they can be easily defined on top of the fixed duration datatype. And they should be specified separately from the base functionality. Certainly, differences between clock times should be in terms of the fixed-duration datatype. SM The TimeExts library gives you separate differences like SM these, BTW. That sounds good, I'll look at it again (it's pretty much bare code, so I might have overlooked something). 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. SM That's right, and here I'm not sure whether the right behaviour is to SM raise an exception or to roll over to the next nearest date/time. I SM believe TimeExts does some kind of rolling over, but I'm not sure of the SM exact semantics (George?). As far as I read ISO8601 (which also has a notation for durations) this is unspecifed :-) And as far as I read TimeExts.lhs it does some sort of rollover. My take would be to specify the behavior for adding something like a TimeDiff to a base date in a consistent manner and then cast that in stone. If there is a (reasonable) standard for this kind of calculation, then this should be the basis for the specification. SM Ok, ISO8601 seems to specify only constant-duration time intervals, but SM allows them to be given in terms of years, months, days etc., where a SM month is specified to be 30 days, it seems, and similar SM approximations If I remember correctly, then ISO8601 specifies durations up to a day, but bails out at months and years. Agreed! So what is epoch? Is it Seconds since 00:00:00 on 1 Jan 1970 [TAI]? SM I guess so... GHC's implementation will be whatever the C library uses, SM which I assume is the one you specified above (at least on a decent SM implementation). Unfortunately, if you are using time(2), then you'll get rubbish (from the manual page): DESCRIPTION time returns the time since the Epoch (00:00:00 UTC, Jan uary 1, 1970), measured in seconds. [...] NOTES POSIX.1 defines seconds since the Epoch as a value to be interpreted as the number of seconds between a specified time and the Epoch, according to a formula for conversion from UTC equivalent to conversion on the naïve basis that leap seconds are ignored and all years divisible by 4 are leap years. This value is not the same as the actual num ber of seconds between the time and the Epoch, because of leap seconds and because clocks are not required to be synchronised to a standard reference. The intention is that the interpretation of seconds since the Epoch values be consistent; see POSIX.1 Annex B 2.2.2 for further rationale. The problem is that this notion of time is discontinuous and sometimes not strictly increasing. See the various references pointed out by members of the list for why this can be a problem. -Peter PS, I see you are trying to follow-up to haskell-cafe, but I'm not subscribed to that list. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Peter Thiemann (Thu, Feb 06, 2003 at 12:40:14PM -0800): John's code illustrates TimeDiff's deficiencies perfectly: There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. What time takes a year - 365 or 366 days? There are leap years! What time takes a month - 28, 29, 30 or 31 days? A week takes 7 days. How long is a day - 86399, 86400 or 86401 seconds and how long is a hour - 3599, 3600 or 3601 seconds? There are leap seconds! A second is the basic amount of time. My conclusion is that time differences really should be measured in seconds and picoseconds. How do you measure 100 attoseconds? type TimeDiff = (Integer, Integer) More general is newtype TimeDiff = TimeDiff Rational deriving (Eq, Ord) Hmm, this is underspecified! As another poster said, (pointing out http://cr.yp.to/libtai, but it is better to look at http://cr.yp.to/time.html, which has a discussion on UTC vs TAI vs UNIX time) the official source of time is TAI, so it is best to base a time library *on the number of TAI seconds since a reference date* (which is btw what the libtai is all about). For compatibility with UNIX time, Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI [http://cr.yp.to/proto/utctai.html]. So this mostly means that you need to set your system clock correctly:-) No, you have to check for leap seconds. There is one in every few years. Hence, a suitable specification for JM toRawTime :: ClockTime - (Integer,Integer) could be number of seconds since reference point, given as a pair (full seconds, picoseconds). This function *may* involve a time zone calculation for those that do not run their system clock on TAI (or UTC). JM fromRawTime :: (Integer,Integer) - ClockTime with toRawTime . fromRawTime == id and fromRawTime . toRawTime ~~ id (the internal representation of ClockTime may have less precision, so the difference would be less than system dependent constant, which could also be supplied by the library) Given these two raw ingredients, everything else can be computed from that. In addition, it would be nice to have parsing functions for various time and date formats (which is what I ended up writing myself for the ISO8601 format). Cheers, -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Peter Thiemann (Fri, Feb 07, 2003 at 10:22:12AM -0800): SM == Simon Marlow [EMAIL PROTECTED] writes: 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. 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. IMHO, you need two different functions to add time. One that add the absolute time difference (as TAI seconds). Another one add calendar times and rounds down as needed, e.g. (timediff calTime1 calTime2) :: TimeDiff (in years, months, etc.) floorTimeAdd '2000-01-31' (Month 1) == '2000-02-28' floorTimeAdd '2004-01-31' (Month 1) == '2000-02-29' -- a leap year Suppose a leap second: floorTimeAdd '2000-01-31.23:59:60' (Minute 1) == '2000-02-01.00:00:59' Cheers, -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: time since the epoch
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 ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: time since the epoch
Matthew Donadio (Fri, Feb 07, 2003 at 01:13:30PM -0500): Pretty much the whole world runs on UTC. All of the common time distribution systems use UTC. Technically, GPS doesn't, but the GPS signal includes the correction to UTC. I understand the argument for using TAI. Maybe internally the libray should use TAI, but default to giving the user UTC? Yes, TAI should be the base to add seconds. (It's a total function!) Two functions should connect it to UTC, e.g.: taiutc :: UTCleaps - TAItime - (UTCtime, Bool {-isLeap-}) utctai :: UTCleaps - Bool {- isLeap -} - UTCtime - TAItime where newtype UTCleaps = UTCleaps ( [ (TAItime,Bool {- Skipped or Additional -}) ], TAItime {- valid (at least) until -} ) newtype UTCtime = UTCtime Rational Note: o It is easy to use (utctai leaps False) and (\t - first (taiutc leaps t)) as a simple interface. o Only, programs that run several month have to update the leap-seconds table more than once. On UTCtime we can build ISO, Gregorian, Julian, etc. calendars. Cheers, -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Keith Wansbrough (Thu, Feb 06, 2003 at 05:46:22PM +): Stefan Karrmann [EMAIL PROTECTED] writes: A sound base for a Time implementation should use TAI (temps atomique international), c.f. http://cr.yp.to/libtai.html. I disagree; I think UTC is quite sufficient, and will match the users' expectations much better. (executive summary: UTC is the time on your watch (+/- timezone of course), TAI is behind by a few seconds, and this difference changes each time there's a new leap second). However, the reference above is not to TAI, but to a library called libtai. I don't know anything about this; Stefan, maybe you could tell us some more? One TAI second is defined as the duration of 9192631770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the cesium atom (quoted from http://cr.yp.to/libtai/tai64.html). Therefore, it is easy to add seconds to a TAI-label. If you have a leap-second table, you can easily convert TAI into UTC but not visa-versa (afaik), since in UTC leap-seconds are mapped to the previous second! (You need a leap-flag.) From UTC to CalenderTime (Gregorian (from 1582) or ISO time) is straight forward. Libtai is a public domain implementation of 64-bit TAI-labels, which are defined from 1E+11 years before 1970 to 1E+11 years after 1970. Thus this would avoid year 2038 and 2036 bugs of other common time representations. References (some may moved into nirwana): 1. http://www.boulder.nist.gov/timefreq/general/glossary3.htm 2. http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm 3. http://sadira.gb.nrao.edu/~rfisher/Ephemerides/times.html 4. http://purl.org/DC/elements/1.1/ Sincerly, -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Hi all, I'm jumping into this a bit late, but I have some good info about time. Two sites that I know about that have good tutorials and white papers are http://www.datum.com/res_technical.html http://www.truetime.com/DOCSn/TTreferencematerial.html In particlar, the paper Timing and Time Code Reference Book is very interesting. It explains several different time standards that are currently used, and tells you why UTC needs leap seconds. Pretty much the whole world runs on UTC. All of the common time distribution systems use UTC. Technically, GPS doesn't, but the GPS signal includes the correction to UTC. I understand the argument for using TAI. Maybe internally the libray should use TAI, but default to giving the user UTC? -- Matthew Donadio ([EMAIL PROTECTED]) ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Matthew Donadio wrote: Pretty much the whole world runs on UTC. All of the common time distribution systems use UTC. Technically, GPS doesn't, but the GPS signal includes the correction to UTC. I understand the argument for using TAI. Maybe internally the libray should use TAI, but default to giving the user UTC? I'd argue that the most important factor is compatibility with the rest of the OS. If the underlying OS doesn't support leap seconds, then nor should the Haskell environment. IOW, the Haskell functions need to be wrappers around the corresponding libc functions (or their Windows equivalents). I.e.: Haskell C getClockTimegettimeofday toCalendarTime localtime toUTCTime gmtime toClockTime mktime -- Glynn Clements [EMAIL PROTECTED] ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
SM == Simon Marlow [EMAIL PROTECTED] writes: Ha! After playing with this, I discovered that only the seconds were set and all other fields remained untouched. At least in ghc's implementation. Interestingly, TimeDiff derives Eq and Ord, but I'd better not ask for their implementation... 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. As an aside, you can easily define convenience functions that map your (application's) idea of months and years to seconds, but it would be much harder the other way round. There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. 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. 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. 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. My conclusion is that time differences really should be measured in seconds and picoseconds. type TimeDiff = (Integer, Integer) SM We already have this kind of TimeDiff: just don't use anything except SM the seconds and picoseconds fields. Indeed, I found by experimentation that diffClockTimes only fills in these two fields so that my attempt to compare the result with TimeDiff{ 0... tdDay = 14 ... 0 } was doomed. Unfortunately, the tdSec field has type Int, so its range is too small to be useful. SM I agree with John Meacham in that it ought to be possible to get a raw SM time in terms of seconds/picoseconds since the epoch, and indeed GHC SM lets you do that: importing System.Time lets you get at the SM representation of ClockTime: SM data ClockTime SM = TOD Integer -- Seconds since 00:00:00 on 1 Jan 1970 SM Integer -- Picoseconds with the specified second 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] ? ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Simon Peyton-Jones (Mon, Feb 03, 2003 at 10:06:40AM -): | the haskell 98 time library is horribly broken, if you are using ghc, | you can deconstruct the time constructor which has an Integer containing | the number of seconds since epoch... otherwise you can use | ... | I dont supose this could be considered a typo in the haskell 98 report? | it is an embarasing thing for a language to not be able to do... Meanwhile, I suspect there's an opportunity for someone (or a small group) to suggest a new Time library that really does the business, and provide an implementation. If it's sufficiently persuasive, all the implementations will adopt it and it can become a de-facto standard. A sound base for a Time implementation should use TAI (temps atomique international), c.f. http://cr.yp.to/libtai.html. The implementation is important because Time is a weird enough thing that only an expert can implement the spec! -- Stefan Karrmann ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
Stefan Karrmann [EMAIL PROTECTED] writes: A sound base for a Time implementation should use TAI (temps atomique international), c.f. http://cr.yp.to/libtai.html. I disagree; I think UTC is quite sufficient, and will match the users' expectations much better. (executive summary: UTC is the time on your watch (+/- timezone of course), TAI is behind by a few seconds, and this difference changes each time there's a new leap second). However, the reference above is not to TAI, but to a library called libtai. I don't know anything about this; Stefan, maybe you could tell us some more? --KW 8-) ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
[Keith Wansbrough [EMAIL PROTECTED]] Stefan Karrmann [EMAIL PROTECTED] writes: A sound base for a Time implementation should use TAI (temps atomique international), c.f. http://cr.yp.to/libtai.html. I disagree; I think UTC is quite sufficient, and will match the users' expectations much better. (executive summary: UTC is the time on your watch (+/- timezone of course), TAI is behind by a few seconds, and this difference changes each time there's a new leap second). However, the reference above is not to TAI, but to a library called libtai. I don't know anything about this; Stefan, maybe you could tell us some more? I know it's not really on topic, but for those of us who are ignorant of the details of time standards, does anyone have a pointer to a decent conceptual (i.e., non-software specific) overview of the subject? Leap seconds, etc., are all pretty much new to me, but I am curious. Matt -- Matt Hellige [EMAIL PROTECTED] http://matt.immute.net ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
I've been running into similar problems, and I've also been pointed to the TimeExt library that George Russell was talking about. However, in the end, I had to implement something by myself. Much unfortunately though, my program relies on an undocumented feature of GHC's implementation of TimeDiff in the Time library. John's code illustrates TimeDiff's deficiencies perfectly: JM the haskell 98 time library is horribly broken, if you are using ghc, JM you can deconstruct the time constructor which has an Integer containing JM the number of seconds since epoch... otherwise you can use JM epoch :: ClockTime JM epoch = toClockTime $ CalendarTime { ctYear = 1970, ctMonth = January, JM ctDay = 0, ctHour = 0, ctMin = 0, ctSec = 0, ctTZ = 0, ctPicosec = 0, JM ctWDay = undefined, ctYDay = undefined, ctTZName = undefined, ctIsDST = JM undefined} JM and TimeDiff, JM unfortunatly you have to condense the TimeDiff to seconds, which is JM unfeasable... Ha! After playing with this, I discovered that only the seconds were set and all other fields remained untouched. At least in ghc's implementation. Interestingly, TimeDiff derives Eq and Ord, but I'd better not ask for their implementation... There is also a more fundamental problem with the TimeDiff data type. While seconds, minutes, hours, and days are clearly specified amounts of time, the duration of a month or a year may vary depending on the reference point where the time difference is applied. My conclusion is that time differences really should be measured in seconds and picoseconds. type TimeDiff = (Integer, Integer) JM we really should fix the Haskell time library. I propose adding: JM toRawTime :: ClockTime - (Integer,Integer) JM fromRawTime :: (Integer,Integer) - ClockTime JM where the integers are the number of seconds and picoseconds since JM epoch, these would be enough to make the time library useful. JM I dont supose this could be considered a typo in the haskell 98 report? JM it is an embarasing thing for a language to not be able to do... Hmm, this is underspecified! As another poster said, (pointing out http://cr.yp.to/libtai, but it is better to look at http://cr.yp.to/time.html, which has a discussion on UTC vs TAI vs UNIX time) the official source of time is TAI, so it is best to base a time library *on the number of TAI seconds since a reference date* (which is btw what the libtai is all about). For compatibility with UNIX time, Arthur David Olson's popular time library uses an epoch of 1970-01-01 00:00:10 TAI [http://cr.yp.to/proto/utctai.html]. So this mostly means that you need to set your system clock correctly:-) Hence, a suitable specification for JM toRawTime :: ClockTime - (Integer,Integer) could be number of seconds since reference point, given as a pair (full seconds, picoseconds). This function *may* involve a time zone calculation for those that do not run their system clock on TAI (or UTC). JM fromRawTime :: (Integer,Integer) - ClockTime with toRawTime . fromRawTime == id and fromRawTime . toRawTime ~~ id (the internal representation of ClockTime may have less precision, so the difference would be less than system dependent constant, which could also be supplied by the library) Given these two raw ingredients, everything else can be computed from that. In addition, it would be nice to have parsing functions for various time and date formats (which is what I ended up writing myself for the ISO8601 format). Cheers, -Peter ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: time since the epoch
| the haskell 98 time library is horribly broken, if you are using ghc, | you can deconstruct the time constructor which has an Integer containing | the number of seconds since epoch... otherwise you can use | ... | I dont supose this could be considered a typo in the haskell 98 report? | it is an embarasing thing for a language to not be able to do... Alas, no. CUP is, even as I type, printing the Haskell 98 Report. We'll have to think about how to accumulate further bugs/suggestions for H98. Meanwhile, I suspect there's an opportunity for someone (or a small group) to suggest a new Time library that really does the business, and provide an implementation. If it's sufficiently persuasive, all the implementations will adopt it and it can become a de-facto standard. The implementation is important because Time is a weird enough thing that only an expert can implement the spec! I think the current Time library suffered because no one who Really Cared about time was involved in its design or implementation. Simon ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: time since the epoch
Simon PJ wrote (snipped) Meanwhile, I suspect there's an opportunity for someone (or a small group) to suggest a new Time library that really does the business, and provide an implementation. If it's sufficiently persuasive, all the implementations will adopt it and it can become a de-facto standard. I already have written a TimeExts library which is in fact bundled with GHC, namely in -package lang. What I ought to do, I suppose, is fishify the comments so Haddock can produce something useful. Basically it allows you to add a time difference to a ClockTime value to get another ClockTime value, or subtract two ClockTime values to get a time difference. The time difference can be a number of picoseconds, seconds, minutes, hours, days, months or years. For all but seconds and picoseconds, it does this by converting to CalendarTime (using toUTCTime), doing complicated Gregorian calendar calculations (I am not proud of the code here), and then converting back using toClockTime. This is probably not a very good way of doing it but at least no-one has complained about it so far. Which means either it's perfect or no-one uses it, I fear the latter. At least it might be a good idea to start with something like this code, rather than reinventing the wheel. Things you need to watch out for are (a) leap seconds; (b) time zones. I didn't really address the time zone problem, instead doing everything in UTC. For us Europeans, it doesn't normally make any difference whether you use local or UTC time when you ask for the date one month from now. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: time since the epoch
the haskell 98 time library is horribly broken, if you are using ghc, you can deconstruct the time constructor which has an Integer containing the number of seconds since epoch... otherwise you can use epoch :: ClockTime epoch = toClockTime $ CalendarTime { ctYear = 1970, ctMonth = January, ctDay = 0, ctHour = 0, ctMin = 0, ctSec = 0, ctTZ = 0, ctPicosec = 0, ctWDay = undefined, ctYDay = undefined, ctTZName = undefined, ctIsDST = undefined} and TimeDiff, unfortunatly you have to condense the TimeDiff to seconds, which is unfeasable... we really should fix the Haskell time library. I propose adding: toRawTime :: ClockTime - (Integer,Integer) fromRawTime :: (Integer,Integer) - ClockTime where the integers are the number of seconds and picoseconds since epoch, these would be enough to make the time library useful. I dont supose this could be considered a typo in the haskell 98 report? it is an embarasing thing for a language to not be able to do... John On Fri, Jan 31, 2003 at 04:20:29PM -0500, Mike T. Machenry wrote: I am looking for a simple way to get the current days sincethe epoch. Most language's standard time library have a get-seconds function that returns the number of seconds since the epoch, thus the function is for example in scheme: (define (days-since-epoch) ((get-seconds) / (* 60 60 24))) But it seems that in haskell the standard definition for the time library will not give me seconds since the epoch. There is technically enough information in the CalendarTime structure to calculate it, but it is a pretty complicated algorithm. Not to mention the fact that it is the exact opposite of the algorithm used to get that information in the first place, so I'd like to not have to undo it and just get the seconds as they are. Thanks for the help -mike ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell -- --- John Meacham - California Institute of Technology, Alum. - [EMAIL PROTECTED] --- ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell