{-# LANGUAGE DeriveLift #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-| Copyright : (c) Ryota Kameoka, 2018 License : BSD-3 Maintainer : kameoka.ryota@gmail.com Stability : experimental This module exports internally used type classes and data types. You can extend this package's functionality by utilizing them. -} module Data.Time.Clock.Duration.Types ( -- * Type classes AbsoluteDuration (..) , RelativeDuration (..) -- * Data types , Time (..) ) where import Data.Int (Int8, Int16, Int32, Int64) import Data.Fixed (E6, E12, Fixed, HasResolution (resolution)) import Data.Proxy (Proxy (Proxy)) import Data.Ratio (Ratio) import Data.Time.Clock (DiffTime, NominalDiffTime, picosecondsToDiffTime) import Foreign.C.Types (CSUSeconds (CSUSeconds), CUSeconds (CUSeconds)) import Language.Haskell.TH.Syntax (Lift) -- $setup -- >>> :set -XQuasiQuotes -- >>> import Data.Time.Clock.Duration.QQ -- | The 'AbsoluteDuration' class provides how to convert the given 'Time' into a specific unit of time. -- An instance should represent a quantity with -- . -- -- 42 seconds in 'DiffTime' (seconds): -- -- >>> [t| 42s |] :: DiffTime -- 42s -- -- 42 seconds in 'CUSeconds' (microseconds): -- -- >>> [t| 42s |] :: CUSeconds -- 42000000 class AbsoluteDuration a where toAbsoluteDuration :: Time -> a instance AbsoluteDuration DiffTime where toAbsoluteDuration = picosecondsToDiffTime . round . inPsScale . toSeconds instance AbsoluteDuration NominalDiffTime where toAbsoluteDuration = realToFrac . toAbsoluteDuration @DiffTime -- | /Caution:/ the fractional part will be rounded. instance AbsoluteDuration CUSeconds where toAbsoluteDuration = CUSeconds . round . inµsScale . toSeconds -- | /Caution:/ the fractional part will be rounded. instance AbsoluteDuration CSUSeconds where toAbsoluteDuration = CSUSeconds . round . inµsScale . toSeconds -- | The 'RelativeDuration' class represents how to calculate how long the given 'Time' is when -- measured in a specific unit of time. -- An instance should represent a quantity with -- . -- -- 42 minutes in seconds: -- -- >>> [s| 42m |] :: Int -- 2520 -- -- 3 seconds in microseconds: -- -- >>> [µs| 3s |] :: Int -- 3000000 class RelativeDuration a where toRelativeDuration :: HasResolution r => Proxy r -> Time -> a -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Int where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Int8 where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Int16 where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Int32 where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Int64 where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance RelativeDuration Integer where toRelativeDuration proxy = round . convertScale proxy . toSeconds -- | /Caution:/ the fractional part will be rounded. instance HasResolution a => RelativeDuration (Fixed a) where toRelativeDuration proxy = realToFrac . convertScale proxy . toSeconds instance Integral a => RelativeDuration (Ratio a) where toRelativeDuration proxy = realToFrac . convertScale proxy . toSeconds instance RelativeDuration Float where toRelativeDuration proxy = realToFrac . convertScale proxy . toSeconds instance RelativeDuration Double where toRelativeDuration proxy = realToFrac . convertScale proxy . toSeconds -- | The parsing result of a string inside a quasiquoter. data Time = Picosec Rational | Nanosec Rational | Microsec Rational | Millisec Rational -- ^ Denoted by @ms@, @msec@, @msecs@, @millisecond@, or @milliseconds@ | Second Rational -- ^ Denoted by @s@, @sec@, @secs@, @second@, or @seconds@ | Minute Rational -- ^ Denoted by @m@, @min@, @mins@, @minute@, or @minutes@ | Hour Rational -- ^ Denoted by @h@, @hr@, @hrs@, @hour@, or @hours@ | Day Rational -- ^ Denoted by @d@, @day@, or @days@ | Week Rational -- ^ Denoted by @w@, @week@, or @weeks@ | Year Rational -- ^ Denoted by @y@, @yr@, @yrs@, @year@, or @years@ deriving (Lift) toSeconds :: Time -> Rational toSeconds (Picosec x) = x / 1000000000000 toSeconds (Nanosec x) = x / 1000000000 toSeconds (Microsec x) = x / 1000000 toSeconds (Millisec x) = x / 1000 toSeconds (Second x) = x toSeconds (Minute x) = x * 60 toSeconds (Hour x) = x * 60 * 60 toSeconds (Day x) = x * 60 * 60 * 24 toSeconds (Week x) = x * 60 * 60 * 24 * 7 toSeconds (Year x) = x * 60 * 60 * 24 * 365 convertScale :: forall r. (HasResolution r) => Proxy r -> Rational -> Rational convertScale _ = (* fromIntegral (resolution (0 :: Fixed r))) inPsScale :: Rational -> Rational inPsScale = convertScale (Proxy :: Proxy E12) inµsScale :: Rational -> Rational inµsScale = convertScale (Proxy :: Proxy E6)