o-clock 1.2.1.1 → 1.3.0
raw patch · 5 files changed
+90/−17 lines, 5 filesdep ~basedep ~hedgehogdep ~tasty-hedgehognew-uploader
Dependency ranges changed: base, hedgehog, tasty-hedgehog
Files
- CHANGELOG.md +13/−0
- o-clock.cabal +6/−6
- src/Time/Timestamp.hs +3/−3
- src/Time/Units.hs +49/−5
- test/Test/Time/Units.hs +19/−3
CHANGELOG.md view
@@ -9,6 +9,19 @@ o'clock uses [PVP Versioning][1]. The change log is available [on GitHub][2]. +Unreleased+=====++1.3.0+=====++* [#129](https://github.com/serokell/o-clock/pull/129)+ + Deprecate `toNum`: may cause accidental flooring.+ + Add the `toFractional` function to avoid the accidental flooring.+ + Change the order of the type variables in the definition of `floorRat` so that the target type comes first.+* [#131](https://github.com/serokell/o-clock/pull/131)+ + Add `ceilingRat` and `ceilingUnit`.+ 1.2.1.1 =====
o-clock.cabal view
@@ -4,7 +4,7 @@ -- SPDX-License-Identifier: MPL-2.0 name: o-clock-version: 1.2.1.1+version: 1.3.0 synopsis: Type-safe time library. description: See README.md for details. homepage: https://github.com/serokell/o-clock@@ -23,8 +23,8 @@ tested-with: GHC == 8.6.5 , GHC == 8.8.3 , GHC == 8.10.4- , GHC == 9.0.1- , GHC == 9.2.1+ , GHC == 9.0.2+ , GHC == 9.2.4 source-repository head type: git@@ -32,7 +32,7 @@ common common-options build-depends:- base >=4.12 && <4.17+ base >=4.12 && <5 ghc-options: -Wall default-language: Haskell2010 @@ -74,10 +74,10 @@ Test.Time.Units build-depends: o-clock- , hedgehog >= 0.6 && < 1.2+ , hedgehog >= 0.6 && < 1.3 , hspec-expectations ^>= 0.8 , tasty >= 0.12 && < 1.5- , tasty-hedgehog >= 0.1 && < 1.2+ , tasty-hedgehog >= 0.1 && < 1.3.2 , tasty-hunit-compat ^>= 0.2 , type-spec >= 0.3.0.1 && < 0.5
src/Time/Timestamp.hs view
@@ -82,9 +82,9 @@ -> 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+-- | Returns the result of multiplying a number by a 'Time' element.+timeMul :: forall (unit :: Rat) .+ RatioNat -> Time unit -> Time unit timeMul n (Time t) = Time (n * t)
src/Time/Units.hs view
@@ -3,8 +3,8 @@ -- SPDX-License-Identifier: MPL-2.0 {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ExplicitForAll #-}@@ -43,7 +43,10 @@ , time , floorUnit , floorRat+ , ceilingUnit+ , ceilingRat , toNum+ , toFractional , sec , ms@@ -80,12 +83,12 @@ import Text.ParserCombinators.ReadPrec (ReadPrec, lift) #ifdef HAS_aeson-import Data.Aeson (ToJSON (..), FromJSON (..), withText)-import Text.Read (readMaybe)+import Data.Aeson (FromJSON (..), ToJSON (..), withText) import qualified Data.Text as Text+import Text.Read (readMaybe) #endif -import Time.Rational (type (*), type (/), type (:%), KnownDivRat, Rat, RatioNat, KnownRat, ratVal)+import Time.Rational (KnownDivRat, KnownRat, Rat, RatioNat, ratVal, type (*), type (/), type (:%)) import qualified Control.Concurrent as Concurrent import qualified System.CPUTime as CPUTime@@ -300,7 +303,7 @@ {-# INLINE fortnight #-} -- | Returns the greatest integer not greater than given 'Time'.-floorRat :: forall (unit :: Rat) b . (Integral b) => Time unit -> b+floorRat :: forall b (unit :: Rat) . Integral b => Time unit -> b floorRat = floor . unTime {- | Similar to 'floor', but works with 'Time' units.@@ -318,6 +321,28 @@ floorUnit :: forall (unit :: Rat) . Time unit -> Time unit floorUnit = time . fromIntegral @Natural . floorRat +-- | Returns the smallest integer greater than or equal to the given 'Time'.+--+-- @since 1.3.0+ceilingRat :: forall b (unit :: Rat) . (Integral b) => Time unit -> b+ceilingRat = ceiling . unTime++{- | Similar to 'ceiling', but works with 'Time' units.++>>> ceilingUnit @Day (Time $ 5 % 2)+3d++>>> ceilingUnit (Time @Second $ 2 % 3)+1s++>>> ceilingUnit $ ps 42+42ps++@since 1.3.0+-}+ceilingUnit :: forall (unit :: Rat) . Time unit -> Time unit+ceilingUnit = time . fromIntegral @Natural . ceilingRat+ {- | Convert time to the 'Num' in given units. For example, instead of writing@@ -348,6 +373,25 @@ toNum :: forall (unitTo :: Rat) n (unit :: Rat) . (KnownDivRat unit unitTo, Num n) => Time unit -> n toNum = fromIntegral @Natural . floorRat . toUnit @unitTo+{-# DEPRECATED toNum+ [ "May lead to unexpected flooring of the fractional time."+ , "Use 'toFractional' to avoid rounding or 'floorRat' to keep the flooring behaviour."+ ] #-}++{- | Convert the 'Time' object to the 'Fractional' value.++__Examples:__++>>> toFractional @Rational $ hour (1 % 8)+1 % 8++>>> toFractional @Double $ hour (1 % 8)+0.125++@since 1.3.0+-}+toFractional :: forall r (unit :: Rat) . Fractional r => Time unit -> r+toFractional = fromRational . toRational . unTime ---------------------------------------------------------------------------- -- Functional
test/Test/Time/Units.hs view
@@ -12,14 +12,16 @@ ) where import Control.Exception (evaluate)-import GHC.Real (Ratio ((:%)))+import GHC.Real (Ratio ((:%)), (%)) import Test.Hspec.Expectations (anyException, shouldBe, shouldThrow) import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit (testCase) -import Time (Day, Hour, Millisecond, Minute, Second, Time (..), Week, day, floorUnit, fortnight,- hour, mcs, minute, ms, ns, ps, sec, seriesF, toUnit, unitsF, week, (+:+)) +import Time (Day, Hour, Millisecond, Minute, Second, Time (..), Week, day, floorUnit, ceilingUnit,+ fortnight, hour, mcs, minute, ms, ns, ps, sec, seriesF, toUnit, toFractional, unitsF,+ week, (+:+))+ unitsTestTree :: TestTree unitsTestTree = testGroup "Units" unitsTests @@ -74,6 +76,20 @@ floorUnit (Time $ 5 :% 2) `shouldBe` day 2 , testCase "returns 42ps when floor integer" $ floorUnit (ps 42) `shouldBe` ps 42+ ]+ , testGroup "Ceiling tests"+ [ testCase "returns 1s, given 2/3 seconds" $+ ceilingUnit (Time @Second $ 2 :% 3) `shouldBe` sec 1+ , testCase "returns 3d, given 2+1/2 days" $+ ceilingUnit (Time $ 5 :% 2) `shouldBe` day 3+ , testCase "returns 42ps, given exactly 42 picoseconds" $+ ceilingUnit (ps 42) `shouldBe` ps 42+ ]+ , testGroup "Conversion to Fractional values"+ [ testCase "The 'Rational' representation of (hour $ 1 % 8) should be equal to 1 % 8" $+ toFractional @Rational (hour (1 % 8)) `shouldBe` 1 % 8+ , testCase "The 'Double' representation of (hour $ 1 % 8) should be equal to 0.125" $+ toFractional @Double (hour (1 % 8)) `shouldBe` 0.125 ] , testGroup "Formatting tests" [ testCase "4000 minutes should be formatted without ending-zeros" $