{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Time.Timestamp
( Timestamp (..)
, fromUnixTime
, timeDiff
, timeAdd
, timeMul
, (*:*)
, timeDiv
, (/:/)
, (+:+)
, (-:-)
, (-%-)
) where
import GHC.Prim (coerce)
import Time.Rational (KnownDivRat, KnownRat, Rat, RatioNat)
import Time.Units (Second, Time (..), sec, toUnit)
newtype Timestamp = Timestamp Rational
deriving (Show, Read, Eq, Ord)
fromUnixTime :: Real a => a -> Timestamp
fromUnixTime = Timestamp . toRational
timeDiff :: forall (unit :: Rat) . KnownDivRat Second unit
=> Timestamp
-> Timestamp
-> (Ordering, Time unit)
timeDiff (Timestamp a) (Timestamp b) =
let (order, r) = ratDiff a b
in (order, toUnit $ sec r)
timeAdd :: forall (unit :: Rat) . KnownDivRat unit Second
=> Time unit
-> Timestamp
-> Timestamp
timeAdd t (Timestamp ts) = Timestamp (toRational (unTime $ toUnit @Second t) + ts)
timeMul :: forall (unit :: Rat) . KnownRat unit
=> RatioNat
-> Time unit
-> Time unit
timeMul n (Time t) = Time (n * t)
infixr 7 *:*
(*:*) :: forall (unit :: Rat) . KnownRat unit
=> RatioNat -> Time unit -> Time unit
(*:*) = timeMul
timeDiv :: forall (unit :: Rat) . KnownRat unit
=> Time unit
-> Time unit
-> RatioNat
timeDiv (Time t1) (Time t2) = t1 / t2
infix 7 /:/
(/:/) :: forall (unit :: Rat) . KnownRat unit
=> Time unit -> Time unit -> RatioNat
(/:/) = timeDiv
infixl 6 +:+
(+:+) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
=> Time unitLeft
-> Time unitResult
-> Time unitResult
t1 +:+ t2 = coerce ((+) :: RatioNat -> RatioNat -> RatioNat) (toUnit @unitResult t1) t2
{-# INLINE (+:+) #-}
infixl 6 -:-
(-:-) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
=> Time unitLeft
-> Time unitResult
-> Time unitResult
t1 -:- t2 = coerce ((-) :: RatioNat -> RatioNat -> RatioNat) (toUnit @unitResult t1) t2
{-# INLINE (-:-) #-}
infix 6 -%-
(-%-) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
=> Time unitLeft
-> Time unitResult
-> (Ordering, Time unitResult)
t1 -%- (Time t2Rat) =
let (Time t1Rat) = toUnit @unitResult t1
(order, rat) = ratDiff (toRational t1Rat) (toRational t2Rat)
in (order, Time rat)
ratDiff :: Rational -> Rational -> (Ordering, RatioNat)
ratDiff r1 r2 =
let order = compare r1 r2
diff = fromRational $ case order of
LT -> r2 - r1
GT -> r1 - r2
EQ -> 0
in (order, diff)