diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,47 @@
 o'clock uses [PVP Versioning][1].
 The change log is available [on GitHub][2].
 
+0.1.0
+=====
+
+* [#85](https://github.com/serokell/o-clock/issues/85):
+  Add `fromUnixTime` function.
+* [#71](https://github.com/serokell/o-clock/issues/71):
+  Add `toNum` function.
+* [#64](https://github.com/serokell/o-clock/issues/64):
+  Add property tests for `unitsP . unitsF ≡ id`
+* [#63](https://github.com/serokell/o-clock/issues/63):
+  Rename `Formatting` module to `Series`.
+  Add `SeriesP` class for parsing time.
+* [#81](https://github.com/serokell/o-clock/issues/81):
+  Rename `TimeStamp` to `Timestamp`.
+* [#60](https://github.com/serokell/o-clock/issues/60):
+  Show fractional as the last argument in the result of `seriesF`.
+* [#76](https://github.com/serokell/o-clock/issues/76):
+  Remove useless instances of `TimeStamp`. Make TimeStamp always deal with
+  `Second`s internally.
+* [#61](https://github.com/serokell/o-clock/issues/61):
+  Change `Show` and `Read` instances for `Time` to use
+  mixed fractions.
+* [#72](https://github.com/serokell/o-clock/issues/72):
+  Move `+:+` and `-:-` to `TimeStamp` module.
+  Make operators `*:*` and `/:/` for `timeMul` and `timeDiv`.
+  Add `-%-` operator. Change `timeAdd` function to work with `TimeStamp`.
+* [#56](https://github.com/serokell/o-clock/issues/56):
+  Add `doctest` to documentation.
+* [#62](https://github.com/serokell/o-clock/issues/62):
+  Add `.ghci` file. Make time creation helpers work with
+  `RatioNat` instead of `Naturals`.
+  Rename `+:` to `+:+` add `-:-`.
+* [#46](https://github.com/serokell/o-clock/issues/46):
+  Introduce `...` type to create custom time unit lists in
+  provided bounds.
+* [#51](https://github.com/serokell/o-clock/issues/51):
+  Add `IsDescending` type family to check lists of time units
+  in `seriesF` function on right order
+* [#45](https://github.com/serokell/o-clock/issues/45):
+  Fix behavior of 0 time passed to `seriesF`.
+
 0.0.0
 =====
 
diff --git a/README.lhs b/README.lhs
--- a/README.lhs
+++ b/README.lhs
@@ -2,6 +2,7 @@
 
 [![Hackage](https://img.shields.io/hackage/v/o-clock.svg)](https://hackage.haskell.org/package/o-clock)
 [![Build status](https://travis-ci.org/serokell/o-clock.svg?branch=master)](https://travis-ci.org/serokell/o-clock)
+[![Stackage Nightly](http://stackage.org/package/o-clock/badge/nightly)](http://stackage.org/nightly/package/o-clock)
 [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/serokell/o-clock/blob/master/LICENSE)
 
 ## Overview
@@ -129,11 +130,18 @@
 After that we can simply print the output we wanted.
 
 Thought we have special function for this kind of formatting purposes `seriesF`.
-So the same result can be gained with the usage of it. Check it out:
+So the similar result (but not rounded) can be gained with the usage of it. Check it out:
 
 ```haskell
 main :: IO ()
 main = do
-    putStrLn $ formatHours 140
-    putStrLn $ seriesF @'[WorkWeek, WorkDay] $ hour 140
+    putStrLn $ "The result:   " ++ formatHours 140
+    putStrLn $ "With seriesF: " ++ (seriesF @'[WorkWeek, WorkDay] $ hour 140)
+```
+
+And the output will be
+
+```haskell ignore
+The result:   3ww2wd
+With seriesF: 3ww2+1/2wd
 ```
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
 
 [![Hackage](https://img.shields.io/hackage/v/o-clock.svg)](https://hackage.haskell.org/package/o-clock)
 [![Build status](https://travis-ci.org/serokell/o-clock.svg?branch=master)](https://travis-ci.org/serokell/o-clock)
+[![Stackage Nightly](http://stackage.org/package/o-clock/badge/nightly)](http://stackage.org/nightly/package/o-clock)
 [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/serokell/o-clock/blob/master/LICENSE)
 
 ## Overview
@@ -129,11 +130,18 @@
 After that we can simply print the output we wanted.
 
 Thought we have special function for this kind of formatting purposes `seriesF`.
-So the same result can be gained with the usage of it. Check it out:
+So the similar result (but not rounded) can be gained with the usage of it. Check it out:
 
 ```haskell
 main :: IO ()
 main = do
-    putStrLn $ formatHours 140
-    putStrLn $ seriesF @'[WorkWeek, WorkDay] $ hour 140
+    putStrLn $ "The result:   " ++ formatHours 140
+    putStrLn $ "With seriesF: " ++ (seriesF @'[WorkWeek, WorkDay] $ hour 140)
+```
+
+And the output will be
+
+```haskell ignore
+The result:   3ww2wd
+With seriesF: 3ww2+1/2wd
 ```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/o-clock.cabal b/o-clock.cabal
--- a/o-clock.cabal
+++ b/o-clock.cabal
@@ -1,5 +1,5 @@
 name:                o-clock
-version:             0.0.0
+version:             0.1.0
 synopsis:            Type-safe time library.
 description:         See README.md for details.
 homepage:            https://github.com/serokell/o-clock
@@ -24,9 +24,9 @@
 library
   hs-source-dirs:      src
   exposed-modules:     Time
-                         Time.Formatting
                          Time.Rational
-                         Time.TimeStamp
+                         Time.Series
+                         Time.Timestamp
                          Time.Units
   ghc-options:         -Wall
   build-depends:       base         >= 4.10  && < 5
@@ -35,6 +35,9 @@
   default-language:    Haskell2010
   default-extensions:  OverloadedStrings
                        RecordWildCards
+                       ScopedTypeVariables
+                       TypeApplications
+                       TypeFamilies
 
 executable play-o-clock
   main-is:             Playground.hs
@@ -51,7 +54,7 @@
   main-is:             Spec.hs
 
   other-modules:       Test.Time.Property
-                       Test.Time.TimeStamp
+                       Test.Time.Timestamp
                        Test.Time.TypeSpec
                        Test.Time.Units
 
@@ -68,6 +71,17 @@
   default-extensions:  OverloadedStrings
                        RecordWildCards
 
+test-suite o-clock-doctest
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Doctest.hs
+
+  build-tool-depends:  doctest:doctest
+  build-depends:       base    >= 4.10 && < 5
+                     , doctest >= 0.13
+                     , Glob    >= 0.9
+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
 
 test-suite readme-test
   type:                exitcode-stdio-1.0
diff --git a/src/Time.hs b/src/Time.hs
--- a/src/Time.hs
+++ b/src/Time.hs
@@ -4,13 +4,13 @@
 -- can be found here: <https://github.com/serokell/o-clock#readme>
 
 module Time
-    ( module Time.Formatting
-    , module Time.Rational
-    , module Time.TimeStamp
+    ( module Time.Rational
+    , module Time.Series
+    , module Time.Timestamp
     , module Time.Units
     ) where
 
-import Time.Formatting
 import Time.Rational
-import Time.TimeStamp
+import Time.Series
+import Time.Timestamp
 import Time.Units
diff --git a/src/Time/Formatting.hs b/src/Time/Formatting.hs
deleted file mode 100644
--- a/src/Time/Formatting.hs
+++ /dev/null
@@ -1,78 +0,0 @@
-{-# LANGUAGE AllowAmbiguousTypes  #-}
-{-# LANGUAGE CPP                  #-}
-{-# LANGUAGE DataKinds            #-}
-{-# LANGUAGE FlexibleContexts     #-}
-{-# LANGUAGE InstanceSigs         #-}
-{-# LANGUAGE Rank2Types           #-}
-{-# LANGUAGE ScopedTypeVariables  #-}
-{-# LANGUAGE TypeApplications     #-}
-{-# LANGUAGE TypeFamilies         #-}
-{-# LANGUAGE TypeOperators        #-}
-{-# LANGUAGE UndecidableInstances #-}
-
-{- | This module introduces function to format time in desired way.
-
-__Examples__
-
->>> seriesF @'[Day, Hour, Minute, Second] (minute 4000)
-"2d18h40m"
-
->>> seriesF @'[Day, Minute, Second] (minute 4000)
-"2d1120m"
-
->>> seriesF @'[Hour, Minute, Second] (sec 3601)
-"1h1s"
-
->>>  seriesF @'[Hour, Second, Millisecond] (Time @Minute $ 3 % 2)
-"90s"
-
--}
-
-module Time.Formatting
-       ( Series (..)
-       , unitsF
-       ) where
-
-import Time.Rational (Rat)
-#if ( __GLASGOW_HASKELL__ >= 804 )
-import Time.Rational (withRuntimeDivRat)
-#endif
-import Time.Units (AllTimes, KnownRatName, Time, floorUnit, toUnit)
-
--- | Class for time formatting.
-class Series (units :: [Rat]) where
-    seriesF :: forall (someUnit :: Rat) . KnownRatName someUnit
-            => Time someUnit
-            -> String
-
-instance Series ('[] :: [Rat]) where
-    seriesF :: Time someUnit -> String
-    seriesF _ = ""
-
-instance (KnownRatName unit, Series units)
-    => Series (unit ': units :: [Rat]) where
-    seriesF :: forall (someUnit :: Rat) . KnownRatName someUnit
-            => Time someUnit
-            -> String
-#if ( __GLASGOW_HASKELL__ >= 804 )
-    seriesF t = let newUnit = withRuntimeDivRat @someUnit @unit $ toUnit @unit t
-#else
-    seriesF t = let newUnit = toUnit @unit t
-#endif
-                    format  = floorUnit newUnit
-                    timeStr = case floor newUnit :: Int of
-                                   0 -> ""
-                                   _ -> show format
-                in timeStr ++ seriesF @units @unit (newUnit - format)
-
-{- | Similar to 'seriesF', but formats using all time units of the library.
-
->>> unitsF $ fortnight 5
-"5fn"
-
->>> unitsF $ minute 4000
-"2d18h40m"
-
--}
-unitsF :: forall unit . KnownRatName unit => Time unit -> String
-unitsF = seriesF @AllTimes
diff --git a/src/Time/Rational.hs b/src/Time/Rational.hs
--- a/src/Time/Rational.hs
+++ b/src/Time/Rational.hs
@@ -5,9 +5,6 @@
 {-# LANGUAGE FlexibleContexts     #-}
 {-# LANGUAGE FlexibleInstances    #-}
 {-# LANGUAGE Rank2Types           #-}
-{-# LANGUAGE ScopedTypeVariables  #-}
-{-# LANGUAGE TypeApplications     #-}
-{-# LANGUAGE TypeFamilies         #-}
 {-# LANGUAGE TypeOperators        #-}
 {-# LANGUAGE UndecidableInstances #-}
 
@@ -27,6 +24,7 @@
        , Gcd
        , Normalize
        , DivRat
+       , type (>=%)
 #endif
 
         -- Utilities
@@ -44,7 +42,7 @@
 import GHC.Natural (Natural)
 import GHC.Real (Ratio ((:%)))
 #if ( __GLASGOW_HASKELL__ >= 804 )
-import GHC.TypeNats (Div, Mod)
+import GHC.TypeNats (Div, Mod, type (<=?))
 #endif
 import GHC.TypeNats (KnownNat, Nat, natVal)
 #if ( __GLASGOW_HASKELL__ >= 804 )
@@ -184,6 +182,27 @@
 -}
 type family Normalize (r :: Rat) :: Rat  where
     Normalize (a :% b) = (a `Div` Gcd a b) :% (b `Div` Gcd a b)
+
+
+{- | Comparison of type-level rationals, as a function.
+
+>>> :kind! (1 :% 42) >=% (5 :% 42)
+(1 :% 42) >=% (5 :% 42) :: Bool
+= 'False
+
+>>> :kind! (5 :% 42) >=% (1 :% 42)
+(5 :% 42) >=% (1 :% 42) :: Bool
+= 'True
+
+>>> :kind! (42 :% 1) >=% (42 :% 1)
+(42 :% 1) >=% (42 :% 1) :: Bool
+= 'True
+
+-}
+infix 4 >=%
+type family (m :: Rat) >=% (n :: Rat) :: Bool where
+    (a :% b) >=% (c :% d) = c * b <=? a * d
+
 #endif
 
 -- | Rational numbers, with numerator and denominator of 'Natural' type.
diff --git a/src/Time/Series.hs b/src/Time/Series.hs
new file mode 100644
--- /dev/null
+++ b/src/Time/Series.hs
@@ -0,0 +1,272 @@
+{-# LANGUAGE AllowAmbiguousTypes  #-}
+{-# LANGUAGE CPP                  #-}
+{-# LANGUAGE DataKinds            #-}
+{-# LANGUAGE FlexibleContexts     #-}
+{-# LANGUAGE FlexibleInstances    #-}
+{-# LANGUAGE InstanceSigs         #-}
+{-# LANGUAGE Rank2Types           #-}
+{-# LANGUAGE TypeOperators        #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+-- | This module introduces function to format and parse time in desired way.
+
+module Time.Series
+       ( AllTimes
+#if ( __GLASGOW_HASKELL__ >= 804 )
+       , type (...)
+#endif
+         -- * Formatting
+       , SeriesF (..)
+       , unitsF
+
+         -- * Parsing
+       , SeriesP (..)
+       , unitsP
+       ) where
+
+import Data.Char (isDigit, isLetter)
+import Text.Read (readMaybe)
+#if ( __GLASGOW_HASKELL__ >= 804 )
+import Data.Kind (Constraint)
+import Data.Type.Bool (type (&&), If)
+import Data.Type.Equality (type (==))
+import GHC.TypeLits (TypeError, ErrorMessage (Text))
+
+import Time.Rational (type (>=%), withRuntimeDivRat)
+#endif
+import Time.Rational (Rat)
+import Time.Units (Day, Fortnight, Hour, KnownRatName, Microsecond, Millisecond, Minute, Nanosecond,
+                   Picosecond, Second, Time (..), Week, floorUnit, toUnit)
+
+-- $setup
+-- >>> import Time.Units (Time (..), fortnight, hour, minute, ms, sec)
+-- >>> import Time.Timestamp ((+:+))
+-- >>> import GHC.Real ((%))
+
+
+
+-- | Type-level list that consist of all times.
+type AllTimes =
+  '[ Fortnight, Week, Day, Hour, Minute, Second
+   , Millisecond , Microsecond, Nanosecond, Picosecond
+   ]
+
+#if ( __GLASGOW_HASKELL__ >= 804 )
+{- | Creates the list of time units in descending order by provided
+the highest and the lowest bound of the desired list.
+Throws the error when time units are not in the right order.
+
+__Usage example:__
+
+>>> seriesF @(Hour ... Second) $ hour 3 +:+ minute 5 +:+ sec 3 +:+ ms 123
+"3h5m3+123/1000s"
+
+-}
+type family (from :: Rat) ... (to :: Rat) :: [Rat] where
+    from ... to = If (IsDescending '[from, to])
+                     (TakeWhileNot to (DropWhileNot from AllTimes))
+                     (TypeError ('Text "Units should be in descending order"))
+
+-- Drops wile not the required time unit in 'AllTimes'.
+type family DropWhileNot (from :: Rat) (units :: [Rat]) :: [Rat] where
+    DropWhileNot x '[] = '[]
+    DropWhileNot x (u ': units) = If (u == x) (u ': units) (DropWhileNot x units)
+
+-- Takes while not equal to the provided bound.
+type family TakeWhileNot (to :: Rat) (units :: [Rat]) :: [Rat] where
+    TakeWhileNot x '[] = '[]
+    TakeWhileNot x (u ': units) = If (u == x) '[u] (u ': TakeWhileNot x units)
+
+-- | Type family for verification of the descending order of the given
+-- list of time units.
+type family IsDescending (units :: [Rat]) :: Bool where
+    IsDescending ('[])     = 'True
+    IsDescending ('[unit]) = 'True
+    IsDescending (unit1 ': unit2 ': units) =
+        (unit1 >=% unit2) && (IsDescending (unit2 ': units))
+
+type family DescendingConstraint (b :: Bool) :: Constraint where
+    DescendingConstraint 'True  = ()  -- empty constraint; always satisfiable
+    DescendingConstraint 'False = TypeError ('Text "List of units should be in descending order")
+#endif
+
+{- | Class for time formatting.
+
+__Examples__
+
+>>> seriesF @'[Day, Hour, Minute, Second] (minute 4000)
+"2d18h40m"
+
+>>> seriesF @'[Day, Minute, Second] (minute 4000)
+"2d1120m"
+
+>>> seriesF @'[Hour, Minute, Second] (sec 3601)
+"1h1s"
+
+>>>  seriesF @'[Hour, Second, Millisecond] (Time @Minute $ 3 % 2)
+"90s"
+
+>>> seriesF @'[Hour, Second] (minute 0)
+"0h"
+
+>>> seriesF @'[Hour, Minute, Second] (Time @Day (2 % 7))
+"6h51m25+5/7s"
+
+The received list should be in descending order. It would be verified at compile-time.
+Example of the error from @ghci@:
+
+#if ( __GLASGOW_HASKELL__ >= 804 )
+>>> seriesF @'[Millisecond, Second] (minute 42)
+...
+    • List of units should be in descending order
+    • In the expression: seriesF @'[Millisecond, Second] (minute 42)
+      In an equation for ‘it’:
+          it = seriesF @'[Millisecond, Second] (minute 42)
+...
+#endif
+
+-}
+class SeriesF (units :: [Rat]) where
+    seriesF :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => Time someUnit
+            -> String
+
+instance SeriesF ('[] :: [Rat]) where
+    seriesF :: Time someUnit -> String
+    seriesF _ = ""
+
+instance (KnownRatName unit) => SeriesF ('[unit] :: [Rat]) where
+    seriesF :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => Time someUnit -> String
+    seriesF t =
+#if ( __GLASGOW_HASKELL__ >= 804 )
+        let newTime = withRuntimeDivRat @someUnit @unit $ toUnit @unit t
+#else
+        let newTime = toUnit @unit t
+#endif
+        in show newTime
+
+instance ( KnownRatName unit
+         , SeriesF (nextUnit : units)
+#if ( __GLASGOW_HASKELL__ >= 804 )
+         , DescendingConstraint (IsDescending (unit ': nextUnit ': units))
+#endif
+         )
+    => SeriesF (unit ': nextUnit ': units :: [Rat]) where
+    seriesF :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => Time someUnit -> String
+#if ( __GLASGOW_HASKELL__ >= 804 )
+    seriesF t = let newUnit = withRuntimeDivRat @someUnit @unit $ toUnit @unit t
+#else
+    seriesF t = let newUnit = toUnit @unit t
+#endif
+                    flooredNewUnit = floorUnit newUnit
+                    timeStr = case flooredNewUnit of
+                                   0 -> ""
+                                   _ -> show flooredNewUnit
+                    nextUnit = newUnit - flooredNewUnit
+                in if nextUnit == 0
+                   then show newUnit
+                   else timeStr ++ seriesF @(nextUnit ': units) @unit nextUnit
+
+{- | Similar to 'seriesF', but formats using all time units of the library.
+
+>>> unitsF $ fortnight 5
+"5fn"
+
+>>> unitsF $ minute 4000
+"2d18h40m"
+
+-}
+unitsF :: forall unit . KnownRatName unit => Time unit -> String
+unitsF = seriesF @AllTimes
+
+{- | Class for time parsing.
+
+Empty string on input will be parsed as 0 time of the required time unit:
+
+>>> seriesP @'[Hour, Minute, Second] @Second ""
+Just (0s)
+
+__Examples__
+
+>>> seriesP @'[Day, Hour, Minute, Second] @Minute "2d18h40m"
+Just (4000m)
+
+>>> seriesP @'[Day, Minute, Second] @Minute "2d1120m"
+Just (4000m)
+
+>>> seriesP @'[Hour, Minute, Second] @Second "1h1s"
+Just (3601s)
+
+>>> seriesP @'[Hour, Second, Millisecond] @Minute "90s"
+Just (1+1/2m)
+
+>>> seriesP @'[Hour, Second] @Second "11ns"
+Nothing
+
+>>> seriesP @'[Hour, Minute] @Minute "1+1/2h"
+Nothing
+
+>>> seriesP @'[Hour, Minute] @Minute "1+1/2m"
+Just (1+1/2m)
+
+>>> seriesP @'[Hour, Minute] @Minute "1h1+1/2m"
+Just (61+1/2m)
+
+__Note:__ The received list should be in descending order. It would be verified at compile-time.
+
+-}
+class SeriesP (units :: [Rat]) where
+    seriesP :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => String -> Maybe (Time someUnit)
+
+instance SeriesP '[] where
+    seriesP _ = Nothing
+
+instance (KnownRatName unit) => SeriesP '[unit] where
+    seriesP :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => String -> Maybe (Time someUnit)
+    seriesP ""  = Just $ Time 0
+    seriesP str = readMaybeTime @unit str
+
+instance ( KnownRatName unit
+         , SeriesP (nextUnit : units)
+#if ( __GLASGOW_HASKELL__ >= 804 )
+         , DescendingConstraint (IsDescending (unit ': nextUnit ': units))
+#endif
+         )
+         => SeriesP (unit ': nextUnit ': units :: [Rat]) where
+    seriesP :: forall (someUnit :: Rat) . KnownRatName someUnit
+            => String -> Maybe (Time someUnit)
+    seriesP ""  = Just $ Time 0
+    seriesP str = let (num, rest)  = span isDigit str
+                      (u, nextStr) = span isLetter rest
+                      maybeT = readMaybeTime @unit $ num ++ u
+                  in case maybeT of
+                         Nothing -> seriesP @(nextUnit ': units) str
+                         Just t  -> (t +) <$> (seriesP @(nextUnit ': units) nextStr)
+
+{- | Similar to 'seriesP', but parses using all time units of the library.
+
+>>> unitsP @Second "1m"
+Just (60s)
+
+>>> unitsP @Minute "2d18h40m"
+Just (4000m)
+
+-}
+unitsP :: forall unit . KnownRatName unit => String -> Maybe (Time unit)
+unitsP = seriesP @AllTimes @unit
+
+----------------------------------------------------------------------------
+-- Util
+----------------------------------------------------------------------------
+
+readMaybeTime :: forall (unit :: Rat) (someUnit :: Rat) . (KnownRatName unit, KnownRatName someUnit)
+              => String -> Maybe (Time someUnit)
+readMaybeTime str =
+#if ( __GLASGOW_HASKELL__ >= 804 )
+    withRuntimeDivRat @unit @someUnit $
+#endif
+        toUnit @someUnit <$> (readMaybe @(Time unit) str)
diff --git a/src/Time/TimeStamp.hs b/src/Time/TimeStamp.hs
deleted file mode 100644
--- a/src/Time/TimeStamp.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-{-# LANGUAGE DataKinds                  #-}
-{-# LANGUAGE ExplicitForAll             #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE TypeFamilies               #-}
-
--- | This module introduces 'TimeStamp' data type
--- and corresponding functions for operations with time.
-
-module Time.TimeStamp
-       ( TimeStamp (..)
-       , timeDiff
-       , timeAdd
-       , timeMul
-       , timeDiv
-       ) where
-
-import Time.Rational (KnownRat, Rat, RatioNat)
-import Time.Units (Time (..))
-
--- | Similar to 'Time' but has no units and can be negative.
-newtype TimeStamp = TimeStamp Rational
-    deriving (Show, Read, Num, Eq, Ord, Enum, Fractional, Real, RealFrac)
-
-
--- | Returns the result of comparison of two 'Timestamp's and
--- the 'Time' of that difference of given time unit.
-timeDiff :: forall (unit :: Rat) . KnownRat unit
-         => TimeStamp
-         -> TimeStamp
-         -> (Ordering, Time unit)
-timeDiff (TimeStamp a) (TimeStamp b) =
-    let order = compare a b
-        d = fromRational $ case order of
-                EQ -> 0
-                GT -> a - b
-                LT -> b - a
-    in (order, d)
-
--- | Returns the result of addition of two 'Time' elements.
-timeAdd :: forall (unit :: Rat) . KnownRat unit
-        => Time unit
-        -> Time unit
-        -> Time unit
-timeAdd = (+)
-
--- | Returns the result of multiplication of two 'Time' elements.
-timeMul :: forall (unit :: Rat) . KnownRat unit
-        => RatioNat
-        -> Time unit
-        -> Time unit
-timeMul n (Time t) = Time (n * t)
-
--- | Returns the result of division of two 'Time' elements.
-timeDiv :: forall (unit :: Rat) . KnownRat unit
-        => Time unit
-        -> Time unit
-        -> RatioNat
-timeDiv (Time t1) (Time t2) = t1 / t2
diff --git a/src/Time/Timestamp.hs b/src/Time/Timestamp.hs
new file mode 100644
--- /dev/null
+++ b/src/Time/Timestamp.hs
@@ -0,0 +1,176 @@
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE ExplicitForAll             #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+-- | This module introduces 'Timestamp' data type
+-- and corresponding functions for operations with time.
+
+module Time.Timestamp
+       ( Timestamp (..)
+       , fromUnixTime
+       , timeDiff
+       , timeAdd
+       , timeMul
+       , (*:*)
+       , timeDiv
+       , (/:/)
+
+         -- * Other operators
+       , (+:+)
+       , (-:-)
+       , (-%-)
+
+       ) where
+
+import Time.Rational (KnownDivRat, KnownRat, Rat, RatioNat)
+import Time.Units (Second, Time (..), sec, toUnit)
+
+-- $setup
+-- >>> import Time.Units (Minute, Second, minute, ms, sec)
+
+-- | Similar to 'Time' but has no units and can be negative.
+newtype Timestamp = Timestamp Rational
+    deriving (Show, Read, Eq, Ord)
+
+-- | Converts unix time to 'Timestamp'.
+fromUnixTime :: Real a => a -> Timestamp
+fromUnixTime = Timestamp . toRational
+
+{- | Returns the result of comparison of two 'Timestamp's and
+the 'Time' of that difference of given time unit.
+
+>>> timeDiff @Second (Timestamp 4) (Timestamp 2)
+(GT,2s)
+
+>>>timeDiff @Minute (Timestamp 4) (Timestamp 2)
+(GT,1/30m)
+
+>>> timeDiff @Second (Timestamp 2) (Timestamp 4)
+(LT,2s)
+
+>>> timeDiff @Minute (Timestamp 2) (Timestamp 4)
+(LT,1/30m)
+
+-}
+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 $ fromRational r)
+
+{- | Returns the result of addition of 'Time' with 'Timestamp' elements.
+
+>>> sec 5 `timeAdd` (Timestamp 4)
+Timestamp (9 % 1)
+
+>>> minute 1 `timeAdd` (Timestamp 5)
+Timestamp (65 % 1)
+
+-}
+timeAdd :: forall (unit :: Rat) . KnownDivRat unit Second
+        => Time unit
+        -> Timestamp
+        -> Timestamp
+timeAdd t (Timestamp ts) = Timestamp (toRational (unTime $ toUnit @Second t) + ts)
+
+-- | Returns the result of multiplication of two 'Time' elements.
+timeMul :: forall (unit :: Rat) . KnownRat unit
+        => RatioNat
+        -> Time unit
+        -> Time unit
+timeMul n (Time t) = Time (n * t)
+
+{- | Operator version of 'timeMul'.
+
+>>> 3 *:* sec 5
+15s
+
+>>> 2 *:* 3 *:* sec 5
+30s
+
+>>> 3 *:* 5 *:* 7 :: Time Second
+105s
+
+>>> ms 2000 +:+ 2 *:* sec 3
+8s
+
+-}
+infixr 7 *:*
+(*:*) :: forall (unit :: Rat) . KnownRat unit
+      => RatioNat -> Time unit -> Time unit
+(*:*) = timeMul
+
+-- | Returns the result of division of two 'Time' elements.
+timeDiv :: forall (unit :: Rat) . KnownRat unit
+        => Time unit
+        -> Time unit
+        -> RatioNat
+timeDiv (Time t1) (Time t2) = t1 / t2
+
+{- | Operator version of 'timeDiv'.
+
+>>> sec 15 /:/ sec 3
+5 % 1
+
+-}
+infix 7 /:/
+(/:/) :: forall (unit :: Rat) . KnownRat unit
+      => Time unit -> Time unit -> RatioNat
+(/:/) = timeDiv
+
+-- | Sums times of different units.
+--
+-- >>> minute 1 +:+ sec 1
+-- 61s
+--
+infixl 6 +:+
+(+:+) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
+      => Time unitLeft
+      -> Time unitResult
+      -> Time unitResult
+t1 +:+ t2 = toUnit t1 + t2
+{-# INLINE (+:+) #-}
+
+-- | Substracts times of different units.
+--
+-- >>> minute 1 -:- sec 1
+-- 59s
+--
+infixl 6 -:-
+(-:-) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
+      => Time unitLeft
+      -> Time unitResult
+      -> Time unitResult
+t1 -:- t2 = toUnit t1 - t2
+{-# INLINE (-:-) #-}
+
+{- | Similar to '-:-' but more safe and returns order in pair with resulting time difference.
+
+>>> sec 5 -%- sec 3
+(GT,2s)
+
+>>> sec 5 -%- sec 6
+(LT,1s)
+
+-}
+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 $ fromRational rat)
+
+ratDiff :: Rational -> Rational -> (Ordering, Rational)
+ratDiff r1 r2 =
+    let order = compare r1 r2
+        diff  = case order of
+                     LT -> r2 - r1
+                     GT -> r1 - r2
+                     EQ -> 0
+    in (order, diff)
diff --git a/src/Time/Units.hs b/src/Time/Units.hs
--- a/src/Time/Units.hs
+++ b/src/Time/Units.hs
@@ -7,9 +7,6 @@
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE InstanceSigs               #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE TypeApplications           #-}
-{-# LANGUAGE TypeFamilies               #-}
 {-# LANGUAGE TypeOperators              #-}
 {-# LANGUAGE UndecidableInstances       #-}
 
@@ -32,8 +29,6 @@
        , Week
        , Fortnight
 
-       , AllTimes
-
        , UnitName
        , KnownUnitName
        , KnownRatName
@@ -42,6 +37,7 @@
         -- ** Creation helpers
        , time
        , floorUnit
+       , toNum
 
        , sec
        , ms
@@ -55,8 +51,6 @@
        , week
        , fortnight
 
-       , (+:)
-
         -- ** Functions
        , toUnit
        , threadDelay
@@ -73,9 +67,9 @@
 import GHC.Natural (Natural)
 import GHC.Prim (coerce)
 import GHC.Read (Read (readPrec))
-import GHC.Real (Ratio ((:%)), denominator, numerator, (%))
+import GHC.Real (denominator, numerator, (%))
 import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
-import Text.ParserCombinators.ReadP (ReadP, char, munch1, option, pfail)
+import Text.ParserCombinators.ReadP (ReadP, char, munch1, option, pfail, (+++))
 import Text.ParserCombinators.ReadPrec (ReadPrec, lift)
 
 #if ( __GLASGOW_HASKELL__ >= 804 )
@@ -126,13 +120,6 @@
 newtype Time (rat :: Rat) = Time { unTime :: RatioNat }
     deriving (Eq, Ord, Enum, Real, RealFrac, Generic)
 
--- | Type-level list that consist of all times.
-type AllTimes =
-  '[ Fortnight, Week, Day, Hour, Minute, Second
-   , Millisecond , Microsecond, Nanosecond, Picosecond
-   ]
-
-
 -- | Type family for prettier 'show' of time units.
 type family UnitName (unit :: Rat) :: Symbol
 
@@ -159,11 +146,25 @@
 unitNameVal = symbolVal (Proxy @(UnitName unit))
 
 instance KnownUnitName unit => Show (Time unit) where
-    show (Time rat) = let numeratorStr   = show (numerator rat)
-                          denominatorStr = case denominator rat of
-                                                1 -> ""
-                                                n -> '/' : show n
-                      in numeratorStr ++ denominatorStr ++ unitNameVal @unit
+    showsPrec p (Time t) = showParen (p > 6)
+                              $ showsMixed t
+                              . showString (unitNameVal @unit)
+      where
+        showsMixed 0 = showString "0"
+        showsMixed rat =
+          let (n,d) = (numerator rat, denominator rat)
+              (q,r) = n `quotRem` d
+              op = if q == 0 || r == 0 then "" else "+"
+              quotStr = if q == 0
+                          then id -- NB id === showString ""
+                          else shows q
+              remStr = if r == 0
+                         then id
+                         else shows r
+                            . showString "/"
+                            . shows d
+          in
+              quotStr . showString op . remStr
 
 instance KnownUnitName unit => Read (Time unit) where
     readPrec :: ReadPrec (Time unit)
@@ -172,11 +173,19 @@
         readP :: ReadP (Time unit)
         readP = do
             let naturalP = read <$> munch1 isDigit
-            n <- naturalP
-            m <- option 1 (char '/' *> naturalP)
+            -- If a '+' is parsed as part of a mixed fraction, the other parts
+            -- are no longer optional.  This separation is required to prevent
+            -- e.g. "3+2" successfully parsing.
+            let fullMixedExpr = (,,) <$> (naturalP <* char '+')
+                                     <*> (naturalP <* char '/')
+                                     <*> naturalP
+            let improperExpr = (,,) 0 <$> naturalP
+                                      <*> option 1 (char '/' *> naturalP)
+            (q,r,d) <- fullMixedExpr +++ improperExpr
+            let n = (q * d + r)
             timeUnitStr <- munch1 isLetter
             unless (timeUnitStr == unitNameVal @unit) pfail
-            pure $ Time (n % m)
+            pure $ Time (n % d)
 
 -- | Has the same behavior as derived instance, but '*' operator
 -- throws the runtime error with 'error'.
@@ -205,87 +214,87 @@
 ----------------------------------------------------------------------------
 
 -- | Creates 'Time' of some type from given 'Natural'.
-time :: Natural -> Time unit
-time n = Time (n :% 1)
+time :: RatioNat -> Time unit
+time n = Time n
 {-# INLINE time #-}
 
 -- | Creates 'Second' from given 'Natural'.
 --
 -- >>> sec 42
--- 42s :: Time Second
-sec :: Natural -> Time Second
+-- 42s
+sec :: RatioNat -> Time Second
 sec = time
 {-# INLINE sec #-}
 
 -- | Creates 'Millisecond' from given 'Natural'.
 --
 -- >>> ms 42
--- 42ms :: Time Millisecond
-ms :: Natural -> Time Millisecond
+-- 42ms
+ms :: RatioNat -> Time Millisecond
 ms = time
 {-# INLINE ms #-}
 
 -- | Creates 'Microsecond' from given 'Natural'.
 --
 -- >>> mcs 42
--- 42mcs :: Time Microsecond
-mcs :: Natural -> Time Microsecond
+-- 42mcs
+mcs :: RatioNat -> Time Microsecond
 mcs = time
 {-# INLINE mcs #-}
 
 -- | Creates 'Nanosecond' from given 'Natural'.
 --
 -- >>> ns 42
--- 42ns :: Time Nanosecond
-ns :: Natural -> Time Nanosecond
+-- 42ns
+ns :: RatioNat -> Time Nanosecond
 ns = time
 {-# INLINE ns #-}
 
 -- | Creates 'Picosecond' from given 'Natural'.
 --
 -- >>> ps 42
--- 42ps :: Time Picosecond
-ps :: Natural -> Time Picosecond
+-- 42ps
+ps :: RatioNat -> Time Picosecond
 ps = time
 {-# INLINE ps #-}
 
 -- | Creates 'Minute' from given 'Natural'.
 --
 -- >>> minute 42
--- 42m :: Time Minute
-minute :: Natural -> Time Minute
+-- 42m
+minute :: RatioNat -> Time Minute
 minute = time
 {-# INLINE minute #-}
 
 -- | Creates 'Hour' from given 'Natural'.
 --
 -- >>> hour 42
--- 42h :: Time Hour
-hour :: Natural -> Time Hour
+-- 42h
+hour :: RatioNat -> Time Hour
 hour = time
 {-# INLINE hour #-}
 
 -- | Creates 'Day' from given 'Natural'.
 --
 -- >>> day 42
--- 42d :: Time Day
-day :: Natural -> Time Day
+-- 42d
+day :: RatioNat -> Time Day
 day = time
 {-# INLINE day #-}
 
 -- | Creates 'Week' from given 'Natural'.
 --
--- >>> sec 42
--- 42w :: Time Week
-week :: Natural -> Time Week
+-- >>> week 42
+-- 42w
+week :: RatioNat -> Time Week
 week = time
 {-# INLINE week #-}
 
 -- | Creates 'Fortnight' from given 'Natural'.
 --
 -- >>> fortnight 42
--- 42fn :: Time Fortnight
-fortnight :: Natural -> Time Fortnight
+-- 42fn
+fortnight :: RatioNat -> Time Fortnight
 fortnight = time
 {-# INLINE fortnight #-}
 
@@ -302,20 +311,39 @@
 
 -}
 floorUnit :: forall (unit :: Rat) . Time unit -> Time unit
-floorUnit = time . floor
+floorUnit = time . fromIntegral @Natural . floor
 
--- | Sums times of different units.
---
--- >>> minute 1 +: sec 1
--- 61s
---
-(+:) :: forall (unitResult :: Rat) (unitLeft :: Rat) . KnownDivRat unitLeft unitResult
-     => Time unitLeft
-     -> Time unitResult
-     -> Time unitResult
-t1 +: t2 = toUnit t1 + t2
-{-# INLINE (+:) #-}
+{- | Convert time to the 'Num' in given units.
 
+For example, instead of writing
+
+@
+foo :: POSIXTime
+foo = 10800  -- 3 hours
+@
+
+one can write more safe implementation:
+
+@
+foo = toNum @Second $ hour 3
+@
+
+__Examples:__
+
+>>> toNum @Second @Natural $ hour 3
+10800
+
+>>> toNum @Minute @Int $ hour 3
+180
+
+>>> toNum @Hour @Natural $ hour 3
+3
+
+-}
+toNum :: forall (unitTo :: Rat) n (unit :: Rat) . (KnownDivRat unit unitTo, Num n)
+      => Time unit -> n
+toNum = fromIntegral @Natural . floor . toUnit @unitTo
+
 ----------------------------------------------------------------------------
 -- Functional
 ----------------------------------------------------------------------------
@@ -329,7 +357,7 @@
 7/1000s
 
 >>> toUnit @Week (Time @Day 45)
-45/7w
+6+3/7w
 
 >>> toUnit @Second @Minute 3
 180s
@@ -352,9 +380,11 @@
  any time-unit and operates in any MonadIO.
 
 
->>> threadDelay $ sec 2
->>> threadDelay (2 :: Time Second)
->>> threadDelay @Second 2
+@
+__>>> threadDelay $ sec 2__
+__>>> threadDelay (2 :: Time Second)__
+__>>> threadDelay @Second 2__
+@
 
 -}
 threadDelay :: forall (unit :: Rat) m . (KnownDivRat unit Microsecond, MonadIO m)
@@ -367,8 +397,11 @@
 -- program in the given time unit.
 -- The precision of this result is implementation-dependent.
 --
--- >>> getCPUTime @Second
+-- @
+-- __>>> getCPUTime @Second__
 -- 1064046949/1000000000s
+-- @
+--
 getCPUTime :: forall (unit :: Rat) m . (KnownDivRat Picosecond unit, MonadIO m)
            => m (Time unit)
 getCPUTime = toUnit . ps . fromInteger <$> liftIO CPUTime.getCPUTime
@@ -377,15 +410,21 @@
 {- | Similar to 'Timeout.timeout' but receiving any time unit
 instead of number of microseconds.
 
->>> timeout (sec 1) (putStrLn "Hello O'Clock")
+@
+__>>> timeout (sec 1) (putStrLn "Hello O'Clock")__
 Hello O'Clock
 Just ()
+@
 
->>> timeout (ps 1) (putStrLn "Hello O'Clock")
+@
+__>>> timeout (ps 1) (putStrLn "Hello O'Clock")__
 Nothing
+@
 
->>> timeout (mcs 1) (putStrLn "Hello O'Clock")
+@
+__>>> timeout (mcs 1) (putStrLn "Hello O'Clock")__
 HellNothing
+@
 
 -}
 timeout :: forall (unit :: Rat) m a . (MonadIO m, KnownDivRat unit Microsecond)
diff --git a/test/Doctest.hs b/test/Doctest.hs
new file mode 100644
--- /dev/null
+++ b/test/Doctest.hs
@@ -0,0 +1,12 @@
+module Main (main) where
+
+import System.FilePath.Glob (glob)
+import Test.DocTest (doctest)
+
+main :: IO ()
+main = do
+    sourceFiles <- glob "src/**/*.hs"
+    doctest $ "-XScopedTypeVariables" : "-XRecordWildCards"
+            : "-XOverloadedStrings"   : "-XDataKinds"
+            : "-XTypeFamilies"        : "-XTypeOperators"
+            : "-XTypeApplications"    : sourceFiles
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -3,7 +3,7 @@
 import Test.Tasty (defaultMain, testGroup)
 
 import Test.Time.Property (hedgehogTestTrees)
-import Test.Time.TimeStamp (timeStampTestTree)
+import Test.Time.Timestamp (timeStampTestTree)
 import Test.Time.TypeSpec (runTypeSpecTests)
 import Test.Time.Units (unitsTestTree)
 
@@ -15,7 +15,7 @@
     -- * toUnit tests
     -- * read tests
     unitTests <- unitsTestTree
-    -- TimeStamp tests
+    -- Timestamp tests
     tsTests   <- timeStampTestTree
 
     let allTests = testGroup "O'Clock" $ [unitTests, tsTests] ++ hedgehogTestTrees
diff --git a/test/Test/Time/Property.hs b/test/Test/Time/Property.hs
--- a/test/Test/Time/Property.hs
+++ b/test/Test/Time/Property.hs
@@ -19,7 +19,7 @@
 
 import Time (Day, Fortnight, Hour, KnownRat, KnownRatName, Microsecond,
              Millisecond, Minute, Nanosecond, Picosecond, Rat, RatioNat, Second,
-             Time (..), Week, toUnit)
+             Time (..), Week, toUnit, unitsF, unitsP)
 #if ( __GLASGOW_HASKELL__ >= 804 )
 import Time (withRuntimeDivRat)
 #endif
@@ -28,7 +28,7 @@
 import qualified Hedgehog.Range as Range
 
 hedgehogTestTrees :: [TestTree]
-hedgehogTestTrees = [readShowTestTree, toUnitTestTree]
+hedgehogTestTrees = [readShowTestTree, toUnitTestTree, seriesTestTree]
 
 readShowTestTree :: TestTree
 readShowTestTree = testProperty "Hedgehog read . show == id" prop_readShowUnit
@@ -36,6 +36,9 @@
 toUnitTestTree :: TestTree
 toUnitTestTree = testProperty "Hedgehog toUnit @to @from . toUnit @from @to ≡ id' property" prop_toUnit
 
+seriesTestTree :: TestTree
+seriesTestTree = testProperty "Hedgehog unitsP . unitsF ≡ id" prop_series
+
 -- | Existential data type for 'Unit's.
 data AnyTime =  forall (unit :: Rat) . (KnownRatName unit)
              => MkAnyTime (Time unit)
@@ -78,6 +81,14 @@
 #endif
                       toUnit (toUnit @unitTo t) === t
 
+-- | Verifier for @ seriesP . seriesF @.
+verifySeries :: forall m . (MonadTest m) => AnyTime -> m ()
+verifySeries (MkAnyTime anyT) = checkSeries anyT
+  where
+    checkSeries :: forall (unit :: Rat) . KnownRatName unit
+                => Time unit -> m ()
+    checkSeries t = unitsP @unit (unitsF t) === Just t
+
 -- | Generates random natural number up to 10^20.
 -- it receives the lower bound so that it wouldn't be possible
 -- to get 0 for denominator.
@@ -108,3 +119,6 @@
     t1 <- genAnyTime
     t2 <- genAnyTime
     verifyToUnit t1 t2
+
+prop_series :: Property
+prop_series = property $ genAnyTime >>= verifySeries
diff --git a/test/Test/Time/TimeStamp.hs b/test/Test/Time/TimeStamp.hs
deleted file mode 100644
--- a/test/Test/Time/TimeStamp.hs
+++ /dev/null
@@ -1,39 +0,0 @@
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE ExplicitNamespaces #-}
-{-# LANGUAGE TypeApplications   #-}
-{-# LANGUAGE TypeOperators      #-}
-
-module Test.Time.TimeStamp
-       ( timeStampTestTree
-       ) where
-
-import Control.Exception (evaluate)
-import Test.Tasty (TestTree)
-import Test.Tasty.Hspec (Spec, anyException, describe, it, shouldBe, shouldThrow, testSpec)
-
-import Time (Day, Hour, Microsecond, Picosecond, Second, TimeStamp (..), Week, timeAdd, timeDiff,
-             timeDiv, timeMul)
-
-timeStampTestTree :: IO TestTree
-timeStampTestTree = testSpec "TimeStamp and time operations" spec_TimeStamp
-
-
-spec_TimeStamp :: Spec
-spec_TimeStamp = do
-    describe "TimeDiff" $ do
-        it "1 is less than 5, diff is 4 seconds" $
-            timeDiff @Second (TimeStamp 1) (TimeStamp 5) `shouldBe` (LT, 4)
-        it "100 is greater that 11, diff is 89 Days" $
-            timeDiff @Day (TimeStamp 100) (TimeStamp 11) `shouldBe` (GT, 89)
-        it "42 is equal to 42, diff is 0 Weeks" $
-            timeDiff @Week (TimeStamp 42) (TimeStamp 42) `shouldBe` (EQ, 0)
-        it "3 hours + 7 hours is 10"  $
-            timeAdd @Hour 3 7 `shouldBe` 10
-        it "twice 21 mcs is 42 mcs"  $
-            timeMul @Microsecond 2 21 `shouldBe` 42
-        it "zero x 42 s is zero"  $
-            timeMul @Second 0 42 `shouldBe` 0
-        it "84 picoseconds divide by 2 is 42"  $
-            timeDiv @Picosecond 84 2 `shouldBe` 42
-        it "fails when trying to divide by zero"  $
-            evaluate (timeDiv @Second 42 0) `shouldThrow` anyException
diff --git a/test/Test/Time/Timestamp.hs b/test/Test/Time/Timestamp.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/Time/Timestamp.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE DataKinds          #-}
+{-# LANGUAGE ExplicitNamespaces #-}
+{-# LANGUAGE TypeApplications   #-}
+{-# LANGUAGE TypeOperators      #-}
+
+module Test.Time.Timestamp
+       ( timeStampTestTree
+       ) where
+
+import Control.Exception (evaluate)
+import Test.Tasty (TestTree)
+import Test.Tasty.Hspec (Spec, anyException, describe, it, shouldBe, shouldThrow, testSpec)
+
+import Time (Hour, Microsecond, Minute, Picosecond, Second, Timestamp (..), Week, timeAdd, timeDiff,
+             timeDiv, timeMul)
+
+timeStampTestTree :: IO TestTree
+timeStampTestTree = testSpec "Timestamp and time operations" spec_Timestamp
+
+
+spec_Timestamp :: Spec
+spec_Timestamp = do
+    describe "TimeDiff" $ do
+        it "1 is less than 5, diff is 4 seconds" $
+            timeDiff @Second (Timestamp 1) (Timestamp 5) `shouldBe` (LT, 4)
+        it "100 is greater that 40, diff is 60 sec == 1 min" $
+            timeDiff @Minute (Timestamp 100) (Timestamp 40) `shouldBe` (GT, 1)
+        it "42 is equal to 42, diff is 0 Weeks" $
+            timeDiff @Week (Timestamp 42) (Timestamp 42) `shouldBe` (EQ, 0)
+        it "3 hours offset 7 is 10"  $
+            timeAdd @Hour 3 (Timestamp 7) `shouldBe` (Timestamp 10807)
+        it "twice 21 mcs is 42 mcs"  $
+            timeMul @Microsecond 2 21 `shouldBe` 42
+        it "zero x 42 s is zero"  $
+            timeMul @Second 0 42 `shouldBe` 0
+        it "84 picoseconds divide by 2 is 42"  $
+            timeDiv @Picosecond 84 2 `shouldBe` 42
+        it "fails when trying to divide by zero"  $
+            evaluate (timeDiv @Second 42 0) `shouldThrow` anyException
diff --git a/test/Test/Time/TypeSpec.hs b/test/Test/Time/TypeSpec.hs
--- a/test/Test/Time/TypeSpec.hs
+++ b/test/Test/Time/TypeSpec.hs
@@ -12,7 +12,7 @@
 
 import Time.Rational ((:%))
 #if ( __GLASGOW_HASKELL__ >= 804 )
-import Time.Rational (type (/), Gcd, Normalize)
+import Time.Rational (type (/), type (>=%), Gcd, Normalize)
 #endif
 import Time.Units (Day, Fortnight, Hour, Microsecond, Millisecond, Minute,
                    Nanosecond, Picosecond, Second, UnitName, Week)
@@ -23,6 +23,7 @@
     print typeSpec_Gcd
     print typeSpec_Normalize
     print typeSpec_DivRat
+    print typeSpec_Compare
 #endif
     print typeSpec_UnitCalculation
     print typeSpec_UnitNames
@@ -90,6 +91,20 @@
      -*- It "5%6 / 25%3 = 1%10" ((5 / 6) / (25 / 3) `Is` (1 :% 10))
 
 typeSpec_DivRat = Valid
+
+typeSpec_Compare ::
+
+  ">=%"
+  ######
+
+    "Comparing"
+    ~~~~~~~~~~~~
+         It "2%7 >=% 2%7 = True"   (((2 :% 7)  >=% (2 :% 7))  `Is` 'True)
+     -*- It "2%7 >=% 7%2 = False"  (((2 :% 7)  >=% (7 :% 2))  `Is` 'False)
+     -*- It "5%42 >=% 1%42 = True" (((5 :% 42) >=% (1 :% 42)) `Is` 'True)
+
+typeSpec_Compare = Valid
+
 #endif
 
 typeSpec_UnitCalculation ::
diff --git a/test/Test/Time/Units.hs b/test/Test/Time/Units.hs
--- a/test/Test/Time/Units.hs
+++ b/test/Test/Time/Units.hs
@@ -14,7 +14,7 @@
 
 import Time (Day, Hour, Microsecond, Millisecond, Minute, Picosecond, Second, Time (..), Week, day,
              floorUnit, fortnight, hour, mcs, minute, ms, ns, ps, sec, seriesF, toUnit, unitsF,
-             week, (+:))
+             week, (+:+))
 
 unitsTestTree :: IO TestTree
 unitsTestTree = testSpec "Units" spec_Units
@@ -45,6 +45,14 @@
             read @(Time Second) "7/2s" `shouldBe` Time (7 :% 2)
         it "fails when '-4s' is expected as seconds" $
             evaluate (read @(Time Second) "-4s") `shouldThrow` anyException
+        it "parses '25+5/7s' as 180/7 seconds" $
+            read @(Time Second) "25+5/7s" `shouldBe` Time (180 :% 7)
+        it "fails when '3+2s' is expected as seconds" $
+            evaluate (read @(Time Second) "3+2s") `shouldThrow` anyException
+        it "fails when '+3s' is expected as seconds" $
+            evaluate (read @(Time Second) "+3s") `shouldThrow` anyException
+        it "fails when '/3s' is expected as seconds" $
+            evaluate (read @(Time Second) "/3s") `shouldThrow` anyException
         it "parses '14/2h' as 7 hours" $
             read @(Time Hour) "14/2h" `shouldBe` 7
         it "fails when '14/2h' expected as 7 seconds" $
@@ -76,9 +84,9 @@
             unitsF (minute 4000) `shouldBe` "2d18h40m"
         it "42 fortnights should be formatted like 42fn" $
             unitsF (fortnight 42) `shouldBe` "42fn"
-        it "empty when receive zero time" $
-            unitsF (Time @Hour 0) `shouldBe` ""
+        it "the first zero time unit when receive zero time" $
+            unitsF (Time @Hour 0) `shouldBe` "0fn"
         it "sums all time units" $
-            unitsF (  fortnight 1 +: week 1 +: day 1 +: hour 1 +: minute 1
-                   +: sec 1 +: ms 1 +: mcs 1 +: ns 1 +: ps 1
+            unitsF (  fortnight 1 +:+ week 1 +:+ day 1 +:+ hour 1 +:+ minute 1
+                  +:+ sec 1 +:+ ms 1 +:+ mcs 1 +:+ ns 1 +:+ ps 1
                    ) `shouldBe` "1fn1w1d1h1m1s1ms1mcs1ns1ps"
