goldfirere / units

The home of the units Haskell package
95 stars 19 forks source link

Relationship of Time to NominalDiffTime #20

Closed spl closed 10 years ago

spl commented 10 years ago

I'm just leaving this here as I ponder it. Food for thought, so to speak.

I wanted to use Time instead of NominalDiffTime, so I came up with:

import qualified Data.Time.Clock as C
addUTCTime :: Time -> UTCTime -> UTCTime
addUTCTime d = C.addUTCTime (realToFrac (d # Second))

Again, this has to do with conversions, as mentioned in #19. I'm not sure if there's a better way to do this.

As I use units and units-defs more, I realize that unit-polymorphism, as you call it, is useful but a lot of other libraries rely on specific units (e.g. microseconds for threadDelay as @jcristovao has wrapped in unbounded-delays-units and seconds with picosecond resolution for NominalDiffTime). Perhaps when you revisit this library, you can think about conversion between quantities of a particular unit and unit-polymorphic quantities. Or maybe we just use fromIntegral and realToFrac.

jcristovao commented 10 years ago

Funny that you mentioned that... Just yesterday I found myself defining this:

import Data.Time.Clock as DTC
diffUTCTime :: DTC.UTCTime -> DTC.UTCTime -> Time
diffUTCTime a b = let
  diff = fromRational . toRational $ DTC.diffUTCTime a b
  in diff %% Second

So, I am not sure what the best approach is here either. We could, for example:

  1. Convince everyone to change to proper units
  2. Convince everyone to define these functions as classes, instantiated to particular time units (Int, or Integer, or units

But I am afraid none of these options is very realistic, given it would be a major breaking change.

So, we're left with duplicate libraries implementing proper time semantics. Either we duplicate a lot of small libraries, like I did with unbounded-delays, or we do a mega-library encompasing probably more than it should (for example, I'm now using this, and I'll probably need the timeout versions too).

So, if there is a smarter way to address this, I would also love to know.

goldfirere commented 10 years ago

I'm not sure what's being asked for here.

Is this another instance of #19? By this, I mean the ability to use integral types to set or extract values from quantities.

Or, is this perhaps a request for better direct interoperability with types from other libraries? For example:

class QuantityLike t unit | t -> unit where
  fromQuantity :: (...) => Qu ... -> t
  toQuantity :: (...) => t -> Qu ...

instance QuantityLike UTCTime Second where ...

and then conversions will be really easy. This QuantityLike option seems quite doable, and may in fact be easier than #19!

In any case, these are good ideas floating around. Thanks for bringing this all up!

nushio3 commented 10 years ago

Measurement of Time has many aspects. For example, if we want to calculate the difference between two events that are years away, upto a precision of seconds, we need to use AbsoluteTime instead of UTCTime, because the former takes leap seconds into account. TAI reflects an aspect of nature that the Earth is gradually spinning down.

units reflects another aspect of time, that it can be raised to powers to construct other quantities.

In my opinion, it is natural that we have many types that represent different aspect of time, and I accept the need of manual conversion between them.

Still, I'm looking forward to QuantityLike proposal by Richard, it will promote easy use of units library, myself will use from/toQuantity a lot.

So, here's a question I don't have an answer: which shall be QuantityLike, DiffTime or NominalDiffTime, or both, or neither?

DiffTime is more accurate difference of time, but to construct them we need leap second table such as found in http://toshi.nofs.navy.mil/ser7/tai-utc.dat . NominalDiffTime is easier to compute, but less accurate (as if (28 Feb.) + 24hr is always (1 Mar.) ). Supporting both may risk unsafe mixup of times.

spl commented 10 years ago

Thanks for the responses, guys.

@goldfirere I think the QuantityLike class sounds potentially useful.

@nushio3 I believe one could use DiffTime or NominalDiffTime, and the reason would depend on the situation. Most use cases are probably involving computer time, not natural time, so UTCTime and thus NominalDiffTime are perhaps more useful.

It is true that the accuracy of NominalDiffTime could reduce that of DiffTime in both are used in a Time. Not sure how to get around that without making Time parameterized and more complicated.

goldfirere commented 10 years ago

My thought here is to avoid the time problem as much as possible -- time is a very hard thing to get right and I want to keep these challenges squarely outside the scope of the units package. That said, it would be great to endow non-units types with the ability to interact with proper quantities. I think the QuantityLike class still feels like the right answer here. My guess is that both DiffTime and NominalDiffTime would end up with QuantityLike instances, and it will be up to users to make sure the streams don't get crossed.

nushio3 commented 10 years ago

Dear @spl and @goldfirere , thank you for the discussion. QuantityLike is a good idea to build interface between units and outer packages so that we can interact better, and now it seems to me that DiffTime and NominalDiffTime are both QuantityLike.

spl commented 10 years ago

Nice, @goldfirere. Thanks.