module Main.Apx where
import Main.Prelude
-- |
-- A wrapper which provides a type-specific 'Eq' instance
-- with approximate comparison.
newtype Apx a = Apx {unApx :: a}
deriving (Show)
instance (Eq (Apx a), Eq (Apx b)) => Eq (Apx (a, b)) where
(==) (Apx (a1, a2)) (Apx (b1, b2)) =
Apx a1 == Apx b1
&& Apx a2 == Apx b2
instance Eq (Apx LocalTime) where
(==) (Apx a) (Apx b) =
Apx (localTimeToSeconds a)
== Apx (localTimeToSeconds b)
instance Eq (Apx UTCTime) where
(==) (Apx a) (Apx b) =
Apx (utcTimeToSeconds a)
== Apx (utcTimeToSeconds b)
instance Eq (Apx TimeOfDay) where
(==) (Apx a) (Apx b) =
Apx (timeOfDayToSeconds a)
== Apx (timeOfDayToSeconds b)
instance Eq (Apx TimeZone) where
(==) (Apx a) (Apx b) =
a == b
instance Eq (Apx Double) where
(==) (Apx a) (Apx b) =
toRational a == toRational b
instance Eq (Apx Rational) where
(==) (Apx a) (Apx b) =
a + error >= b
&& a - error <= b
where
error =
10 ^^ negate 3
utcTimeToSeconds :: UTCTime -> Rational
utcTimeToSeconds (UTCTime days diffTime) =
dayToSeconds days + diffTimeToSeconds diffTime
diffTimeToSeconds :: DiffTime -> Rational
diffTimeToSeconds diffTime =
unsafeCoerce diffTime % (10 ^ 12)
dayToSeconds :: Day -> Rational
dayToSeconds (ModifiedJulianDay day) =
(unsafeCoerce day * 24 * 60 * 60) % 1
localTimeToSeconds :: LocalTime -> Rational
localTimeToSeconds (LocalTime day tod) =
dayToSeconds day
+ timeOfDayToSeconds tod
timeOfDayToSeconds :: TimeOfDay -> Rational
timeOfDayToSeconds (TimeOfDay h m s) =
((toInteger h * 60 + toInteger m) * 60) % 1 + unsafeCoerce s % (10 ^ 12)