-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Type-safe time library.
--   
--   See README.md for details.
@package o-clock
@version 0.1.1


-- | This module introduces <a>Rat</a> kind and all necessary functional.
module Time.Rational

-- | Data structure represents the rational number. Rational number can be
--   represented as a pair of natural numbers <tt>n</tt> and <tt>m</tt>
--   where <tt>m</tt> is nor equal to zero.
data Rat
(::%) :: Nat -> Nat -> Rat

-- | More convenient name for promoted constructor of <a>Rat</a>.
type :% =  '(::%)

-- | The result kind of overloaded multiplication.

-- | The result kind of overloaded division.

-- | Rational numbers, with numerator and denominator of <a>Natural</a>
--   type.
type RatioNat = Ratio Natural

-- | This class gives the integer associated with a type-level rational.
class KnownRat (r :: Rat)
ratVal :: KnownRat r => RatioNat

-- | Constraint alias for <tt>DivRat</tt> units.
type KnownDivRat a b = (KnownRat a, KnownRat b)
instance (GHC.TypeNats.KnownNat a, GHC.TypeNats.KnownNat b) => Time.Rational.KnownRat (a Time.Rational.:% b)


-- | This module contains time unit data structures and functions to work
--   with time.
module Time.Units

-- | Time unit is represented as type level rational multiplier with kind
--   <a>Rat</a>.
newtype Time (rat :: Rat)
Time :: RatioNat -> Time
[unTime] :: Time -> RatioNat
type Second = 1 :% 1
type Millisecond = 1 :% 1000
type Microsecond = 1 :% 1000000
type Nanosecond = 1 :% 1000000000
type Picosecond = 1 :% 1000000000000
type Minute = 60 :% 1
type Hour = 3600 :% 1
type Day = 86400 :% 1
type Week = 604800 :% 1
type Fortnight = 1209600 :% 1

-- | Type family for prettier <a>show</a> of time units.

-- | Constraint alias for <a>KnownSymbol</a> <a>UnitName</a>.
type KnownUnitName unit = KnownSymbol (UnitName unit)

-- | Constraint alias for <a>KnownUnitName</a> and <a>KnownRat</a> for time
--   unit.
type KnownRatName unit = (KnownUnitName unit, KnownRat unit)

-- | Returns type-level <a>Symbol</a> of the time unit converted to
--   <a>String</a>.
unitNameVal :: forall (unit :: Rat). (KnownUnitName unit) => String

-- | Creates <a>Time</a> of some type from given <a>Natural</a>.
time :: RatioNat -> Time unit

-- | Similar to <a>floor</a>, but works with <a>Time</a> units.
--   
--   <pre>
--   &gt;&gt;&gt; floorUnit @Day (Time $ 5 % 2)
--   2d
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; floorUnit (Time @Second $ 2 % 3)
--   0s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; floorUnit $ ps 42
--   42ps
--   </pre>
floorUnit :: forall (unit :: Rat). Time unit -> Time unit

-- | Convert time to the <a>Num</a> in given units.
--   
--   For example, instead of writing
--   
--   <pre>
--   foo :: POSIXTime
--   foo = 10800  -- 3 hours
--   </pre>
--   
--   one can write more safe implementation:
--   
--   <pre>
--   foo = toNum @Second $ hour 3
--   </pre>
--   
--   <b>Examples:</b>
--   
--   <pre>
--   &gt;&gt;&gt; toNum @Second @Natural $ hour 3
--   10800
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toNum @Minute @Int $ hour 3
--   180
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toNum @Hour @Natural $ hour 3
--   3
--   </pre>
toNum :: forall (unitTo :: Rat) n (unit :: Rat). (KnownDivRat unit unitTo, Num n) => Time unit -> n

-- | Creates <a>Second</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; sec 42
--   42s
--   </pre>
sec :: RatioNat -> Time Second

-- | Creates <a>Millisecond</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; ms 42
--   42ms
--   </pre>
ms :: RatioNat -> Time Millisecond

-- | Creates <a>Microsecond</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; mcs 42
--   42mcs
--   </pre>
mcs :: RatioNat -> Time Microsecond

-- | Creates <a>Nanosecond</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; ns 42
--   42ns
--   </pre>
ns :: RatioNat -> Time Nanosecond

-- | Creates <a>Picosecond</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; ps 42
--   42ps
--   </pre>
ps :: RatioNat -> Time Picosecond

-- | Creates <a>Minute</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; minute 42
--   42m
--   </pre>
minute :: RatioNat -> Time Minute

-- | Creates <a>Hour</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; hour 42
--   42h
--   </pre>
hour :: RatioNat -> Time Hour

-- | Creates <a>Day</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; day 42
--   42d
--   </pre>
day :: RatioNat -> Time Day

-- | Creates <a>Week</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; week 42
--   42w
--   </pre>
week :: RatioNat -> Time Week

-- | Creates <a>Fortnight</a> from given <a>Natural</a>.
--   
--   <pre>
--   &gt;&gt;&gt; fortnight 42
--   42fn
--   </pre>
fortnight :: RatioNat -> Time Fortnight

-- | Converts from one time unit to another time unit.
--   
--   <pre>
--   &gt;&gt;&gt; toUnit @Hour (120 :: Time Minute)
--   2h
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toUnit @Second (ms 7)
--   7/1000s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toUnit @Week (Time @Day 45)
--   6+3/7w
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toUnit @Second @Minute 3
--   180s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; toUnit (day 42000000) :: Time Second
--   3628800000000s
--   </pre>
toUnit :: forall (unitTo :: Rat) (unitFrom :: Rat). KnownDivRat unitFrom unitTo => Time unitFrom -> Time unitTo

-- | Convenient version of <a>threadDelay</a> which takes any time-unit and
--   operates in any MonadIO.
--   
--   <pre>
--   <b>&gt;&gt;&gt; threadDelay $ sec 2</b>
--   <b>&gt;&gt;&gt; threadDelay (2 :: Time Second)</b>
--   <b>&gt;&gt;&gt; threadDelay @Second 2</b>
--   </pre>
threadDelay :: forall (unit :: Rat) m. (KnownDivRat unit Microsecond, MonadIO m) => Time unit -> m ()

-- | Similar to <a>getCPUTime</a> but returns the CPU time used by the
--   current program in the given time unit. The precision of this result
--   is implementation-dependent.
--   
--   <pre>
--   <b>&gt;&gt;&gt; getCPUTime @Second</b>
--   1064046949/1000000000s
--   </pre>
getCPUTime :: forall (unit :: Rat) m. (KnownDivRat Picosecond unit, MonadIO m) => m (Time unit)

-- | Similar to <a>timeout</a> but receiving any time unit instead of
--   number of microseconds.
--   
--   <pre>
--   <b>&gt;&gt;&gt; timeout (sec 1) (putStrLn "Hello O'Clock")</b>
--   Hello O'Clock
--   Just ()
--   </pre>
--   
--   <pre>
--   <b>&gt;&gt;&gt; timeout (ps 1) (putStrLn "Hello O'Clock")</b>
--   Nothing
--   </pre>
--   
--   <pre>
--   <b>&gt;&gt;&gt; timeout (mcs 1) (putStrLn "Hello O'Clock")</b>
--   HellNothing
--   </pre>
timeout :: forall (unit :: Rat) m a. (MonadIO m, KnownDivRat unit Microsecond) => Time unit -> IO a -> m (Maybe a)
instance GHC.Generics.Generic (Time.Units.Time rat)
instance GHC.Real.RealFrac (Time.Units.Time rat)
instance GHC.Real.Real (Time.Units.Time rat)
instance GHC.Enum.Enum (Time.Units.Time rat)
instance GHC.Classes.Ord (Time.Units.Time rat)
instance GHC.Classes.Eq (Time.Units.Time rat)
instance Time.Units.KnownUnitName unit => GHC.Show.Show (Time.Units.Time unit)
instance Time.Units.KnownUnitName unit => GHC.Read.Read (Time.Units.Time unit)
instance Data.Semigroup.Semigroup (Time.Units.Time rat)
instance GHC.Base.Monoid (Time.Units.Time rat)
instance GHC.Num.Num (Time.Units.Time unit)
instance GHC.Real.Fractional (Time.Units.Time unit)


-- | This module introduces <a>Timestamp</a> data type and corresponding
--   functions for operations with time.
module Time.Timestamp

-- | Similar to <a>Time</a> but has no units and can be negative.
newtype Timestamp
Timestamp :: Rational -> Timestamp

-- | Converts unix time to <a>Timestamp</a>.
fromUnixTime :: Real a => a -> Timestamp

-- | Returns the result of comparison of two <a>Timestamp</a>s and the
--   <a>Time</a> of that difference of given time unit.
--   
--   <pre>
--   &gt;&gt;&gt; timeDiff @Second (Timestamp 4) (Timestamp 2)
--   (GT,2s)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; timeDiff @Minute (Timestamp 4) (Timestamp 2)
--   (GT,1/30m)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; timeDiff @Second (Timestamp 2) (Timestamp 4)
--   (LT,2s)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; timeDiff @Minute (Timestamp 2) (Timestamp 4)
--   (LT,1/30m)
--   </pre>
timeDiff :: forall (unit :: Rat). KnownDivRat Second unit => Timestamp -> Timestamp -> (Ordering, Time unit)

-- | Returns the result of addition of <a>Time</a> with <a>Timestamp</a>
--   elements.
--   
--   <pre>
--   &gt;&gt;&gt; sec 5 `timeAdd` (Timestamp 4)
--   Timestamp (9 % 1)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; minute 1 `timeAdd` (Timestamp 5)
--   Timestamp (65 % 1)
--   </pre>
timeAdd :: forall (unit :: Rat). KnownDivRat unit Second => Time unit -> Timestamp -> Timestamp

-- | Returns the result of multiplication of two <a>Time</a> elements.
timeMul :: forall (unit :: Rat). KnownRat unit => RatioNat -> Time unit -> Time unit

-- | Operator version of <a>timeMul</a>.
--   
--   <pre>
--   &gt;&gt;&gt; 3 *:* sec 5
--   15s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; 2 *:* 3 *:* sec 5
--   30s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; 3 *:* 5 *:* 7 :: Time Second
--   105s
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; ms 2000 +:+ 2 *:* sec 3
--   8s
--   </pre>
(*:*) :: forall (unit :: Rat). KnownRat unit => RatioNat -> Time unit -> Time unit
infixr 7 *:*

-- | Returns the result of division of two <a>Time</a> elements.
timeDiv :: forall (unit :: Rat). KnownRat unit => Time unit -> Time unit -> RatioNat

-- | Operator version of <a>timeDiv</a>.
--   
--   <pre>
--   &gt;&gt;&gt; sec 15 /:/ sec 3
--   5 % 1
--   </pre>
(/:/) :: forall (unit :: Rat). KnownRat unit => Time unit -> Time unit -> RatioNat
infix 7 /:/

-- | Sums times of different units.
--   
--   <pre>
--   &gt;&gt;&gt; minute 1 +:+ sec 1
--   61s
--   </pre>
(+:+) :: forall (unitResult :: Rat) (unitLeft :: Rat). KnownDivRat unitLeft unitResult => Time unitLeft -> Time unitResult -> Time unitResult
infixl 6 +:+

-- | Substracts time amounts of different units. When the minuend is
--   smaller than the subtrahend, this function will throw <tt>Underflow ::
--   ArithException</tt>.
--   
--   <pre>
--   &gt;&gt;&gt; minute 1 -:- sec 1
--   59s
--   </pre>
(-:-) :: forall (unitResult :: Rat) (unitLeft :: Rat). KnownDivRat unitLeft unitResult => Time unitLeft -> Time unitResult -> Time unitResult
infixl 6 -:-

-- | Compute the difference between two amounts of time. The result is
--   returned in two components: the ordering (which input is larger) and
--   the numeric difference (how much larger). Unlike <a>-:-</a>, does not
--   throw <tt>ArithException</tt>.
--   
--   <pre>
--   &gt;&gt;&gt; sec 5 -%- sec 3
--   (GT,2s)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; sec 5 -%- sec 6
--   (LT,1s)
--   </pre>
(-%-) :: forall (unitResult :: Rat) (unitLeft :: Rat). KnownDivRat unitLeft unitResult => Time unitLeft -> Time unitResult -> (Ordering, Time unitResult)
infix 6 -%-
instance GHC.Classes.Ord Time.Timestamp.Timestamp
instance GHC.Classes.Eq Time.Timestamp.Timestamp
instance GHC.Read.Read Time.Timestamp.Timestamp
instance GHC.Show.Show Time.Timestamp.Timestamp


-- | This module introduces function to format and parse time in desired
--   way.
module Time.Series

-- | Type-level list that consist of all times.
type AllTimes = '[Fortnight, Week, Day, Hour, Minute, Second, Millisecond, Microsecond, Nanosecond, Picosecond]

-- | Class for time formatting.
--   
--   <b>Examples</b>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Day, Hour, Minute, Second] (minute 4000)
--   "2d18h40m"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Day, Minute, Second] (minute 4000)
--   "2d1120m"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Hour, Minute, Second] (sec 3601)
--   "1h1s"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Hour, Second, Millisecond] (Time @Minute $ 3 % 2)
--   "90s"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Hour, Second] (minute 0)
--   "0h"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesF @'[Hour, Minute, Second] (Time @Day (2 % 7))
--   "6h51m25+5/7s"
--   </pre>
--   
--   The received list should be in descending order. It would be verified
--   at compile-time. Example of the error from <tt>ghci</tt>:
--   
--   # 127 "src<i>Time</i>Series.hs"
class SeriesF (units :: [Rat])
seriesF :: forall (someUnit :: Rat). (SeriesF units, KnownRatName someUnit) => Time someUnit -> String

-- | Similar to <a>seriesF</a>, but formats using all time units of the
--   library.
--   
--   <pre>
--   &gt;&gt;&gt; unitsF $ fortnight 5
--   "5fn"
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; unitsF $ minute 4000
--   "2d18h40m"
--   </pre>
unitsF :: forall unit. KnownRatName unit => Time unit -> String

-- | Class for time parsing.
--   
--   Empty string on input will be parsed as 0 time of the required time
--   unit:
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Minute, Second] @Second ""
--   Just (0s)
--   </pre>
--   
--   <b>Examples</b>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Day, Hour, Minute, Second] @Minute "2d18h40m"
--   Just (4000m)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Day, Minute, Second] @Minute "2d1120m"
--   Just (4000m)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Minute, Second] @Second "1h1s"
--   Just (3601s)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Second, Millisecond] @Minute "90s"
--   Just (1+1/2m)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Second] @Second "11ns"
--   Nothing
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Minute] @Minute "1+1/2h"
--   Nothing
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Minute] @Minute "1+1/2m"
--   Just (1+1/2m)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; seriesP @'[Hour, Minute] @Minute "1h1+1/2m"
--   Just (61+1/2m)
--   </pre>
--   
--   <b>Note:</b> The received list should be in descending order. It would
--   be verified at compile-time.
class SeriesP (units :: [Rat])
seriesP :: forall (someUnit :: Rat). (SeriesP units, KnownRatName someUnit) => String -> Maybe (Time someUnit)

-- | Similar to <a>seriesP</a>, but parses using all time units of the
--   library.
--   
--   <pre>
--   &gt;&gt;&gt; unitsP @Second "1m"
--   Just (60s)
--   </pre>
--   
--   <pre>
--   &gt;&gt;&gt; unitsP @Minute "2d18h40m"
--   Just (4000m)
--   </pre>
unitsP :: forall unit. KnownRatName unit => String -> Maybe (Time unit)
instance Time.Series.SeriesP '[]
instance Time.Units.KnownRatName unit => Time.Series.SeriesP '[unit]
instance (Time.Units.KnownRatName unit, Time.Series.SeriesP (nextUnit : units)) => Time.Series.SeriesP (unit : nextUnit : units)
instance Time.Series.SeriesF '[]
instance Time.Units.KnownRatName unit => Time.Series.SeriesF '[unit]
instance (Time.Units.KnownRatName unit, Time.Series.SeriesF (nextUnit : units)) => Time.Series.SeriesF (unit : nextUnit : units)


-- | This module reexports main functionality.
--   
--   More information about <tt>O'Clock</tt> features can be found here:
--   <a>https://github.com/serokell/o-clock#readme</a>
module Time
