diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67fc075..10f021e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: jobs: generate-matrix: name: "Generate matrix from cabal" - outputs: + outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} runs-on: ubuntu-latest steps: @@ -24,14 +24,16 @@ jobs: name: ${{ matrix.ghc }} on ${{ matrix.os }} needs: generate-matrix runs-on: ${{ matrix.os }} + continue-on-error: true strategy: matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }} + fail-fast: false steps: - name: Checkout base repo uses: actions/checkout@v4 - name: Set up Haskell id: setup-haskell - uses: haskell-actions/setup@v2 + uses: haskell-actions/setup@latest with: ghc-version: ${{ matrix.ghc }} cabal-version: 'latest' @@ -40,7 +42,7 @@ jobs: - name: Freeze run: cabal freeze - name: Cache - uses: actions/cache@v3.3.3 + uses: actions/cache@v4 with: path: ${{ steps.setup-haskell.outputs.cabal-store }} key: ${{ runner.os }}-ghc-${{ matrix.ghc }}-cabal-${{ hashFiles('**/plan.json') }} diff --git a/.gitignore b/.gitignore index 39b952d..f711da6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ +.vscode/ *.aux cabal-dev .cabal-sandbox cabal.config cabal.sandbox.config +cabal.project.local *.chi *.chs.h config/client_session_key.aes diff --git a/bench/Bench.hs b/bench/Bench.hs index 4b174fd..76123bb 100644 --- a/bench/Bench.hs +++ b/bench/Bench.hs @@ -7,15 +7,10 @@ module Main where -import Control.Applicative import Criterion.Main -import Data.Int -import Data.Word -import Control.DeepSeq (($!!), NFData(..), deepseq) -import Control.Monad (when) -import Data.Attoparsec.ByteString.Char8 (Parser, parseOnly, char) -import Data.Foldable (traverse_) +import Control.DeepSeq (($!!)) +import Data.Attoparsec.ByteString.Char8 (parseOnly) import Data.Maybe (fromMaybe) import Data.Text.Lazy.Builder (toLazyText) import Data.Text.Short (ShortText) @@ -28,7 +23,6 @@ import qualified Data.Text.Lazy as LT import qualified Data.Text.Short as TS import qualified Data.Thyme as Thyme import qualified Data.Time as Time -import qualified Data.Vector.Unboxed as UVector import qualified System.Locale as Thyme main :: IO () diff --git a/chronos.cabal b/chronos.cabal index 550c400..837d8c9 100644 --- a/chronos.cabal +++ b/chronos.cabal @@ -1,120 +1,128 @@ cabal-version: 3.0 -name: chronos -version: 1.1.5.1 -synopsis: A high-performance time library +name: chronos +version: 1.1.5.1 +synopsis: A high-performance time library description: Chronos is a performance-oriented time library for Haskell, with a straightforward API. The main differences between this and the library are: + * Chronos uses machine integers where possible. This means + that time-related arithmetic should be faster, with the + drawback that the types are incapable of representing times + that are very far in the future or the past (because Chronos + provides nanosecond, rather than picosecond, resolution). + For most users, this is not a hindrance. + * Chronos provides 'ToJSON'/'FromJSON' instances for serialisation. + * Chronos provides 'Unbox' instances for working with unboxed vectors. + * Chronos provides 'Prim' instances for working with byte arrays/primitive arrays. + * Chronos uses normal non-overloaded haskell functions for + encoding and decoding time. It provides parsers for both 'Text' and + 'ByteString'. Additionally, Chronos provides functions for + encoding time to 'Text' or 'ByteString'. The http://hackage.haskell.org/package/time time> library accomplishes these with the + module, which uses UNIX-style datetime + format strings. The approach taken by Chronos is faster and + catches more mistakes at compile time, at the cost of being + less expressive. - * Chronos uses machine integers where possible. This means - that time-related arithmetic should be faster, with the - drawback that the types are incapable of representing times - that are very far in the future or the past (because Chronos - provides nanosecond, rather than picosecond, resolution). - For most users, this is not a hindrance. - * Chronos provides 'ToJSON'/'FromJSON' instances for serialisation. - * Chronos provides 'Unbox' instances for working with unboxed vectors. - * Chronos provides 'Prim' instances for working with byte arrays/primitive arrays. - * Chronos uses normal non-overloaded haskell functions for - encoding and decoding time. It provides parsers for both 'Text' and - 'ByteString'. Additionally, Chronos provides functions for - encoding time to 'Text' or 'ByteString'. The http://hackage.haskell.org/package/time time> library accomplishes these with the - module, which uses UNIX-style datetime - format strings. The approach taken by Chronos is faster and - catches more mistakes at compile time, at the cost of being - less expressive. -homepage: https://github.com/andrewthad/chronos -license: BSD-3-Clause -license-file: LICENSE -author: Andrew Martin +homepage: https://github.com/andrewthad/chronos +license: BSD-3-Clause +license-file: LICENSE +author: Andrew Martin maintainer: Andrew Martin chessai -copyright: 2016 Andrew Martin -category: Data, Time, Parsing, Development -build-type: Simple -tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.4 || ==9.8.1 + +copyright: 2016 Andrew Martin +category: Data, Time, Parsing, Development +build-type: Simple +tested-with: + GHC ==8.10.7 + || ==9.0.2 + || ==9.2.8 + || ==9.4.8 + || ==9.6.3 + || ==9.6.4 + || ==9.8.1 + +common build-settings + default-language: Haskell2010 + ghc-options: -Wall -Wunused-packages library - hs-source-dirs: src + import: build-settings + hs-source-dirs: src exposed-modules: - Chronos - Chronos.Types - Chronos.Locale.English - -- only exposed for doctests - -- it is OPTIONS_HADDOCK-hidden - Chronos.Internal.CTimespec + Chronos + Chronos.Internal.CTimespec + Chronos.Locale.English + Chronos.Types + + -- only exposed for doctests + -- it is OPTIONS_HADDOCK-hidden build-depends: - , aeson >= 1.1 && < 2.3 - , attoparsec >= 0.13 && < 0.15 - , base >= 4.14 && < 4.20 - , bytestring >= 0.10 && < 0.13 - , deepseq >= 1.4.4.0 - , hashable >= 1.2 && < 1.5 - , primitive >= 0.6.4 && < 0.10 - , semigroups >= 0.16 && < 0.21 - , text >= 1.2 && < 1.3 || >= 2.0 && < 2.2 - , torsor >= 0.1 && < 0.2 - , vector >= 0.11 && < 0.14 - , bytebuild >= 0.3.14 && < 0.4 - , bytesmith >= 0.3.7 && < 0.4 - , byteslice >= 0.2.5.2 && <0.3 - , text-short >= 0.1.3 && <0.2 - , natural-arithmetic >= 0.1.2 && <0.3 + , aeson >=1.1 && <2.3 + , attoparsec >=0.13 && <0.15 + , base >=4.14 && <4.20 + , bytebuild >=0.3.14 && <0.4 + , byteslice >=0.2.5.2 && <0.3 + , bytesmith >=0.3.7 && <0.4 + , bytestring >=0.10 && <0.13 + , deepseq >=1.4.4.0 + , hashable >=1.2 && <1.5 + , natural-arithmetic >=0.1.2 && <0.3 + , primitive >=0.6.4 && <0.10 + , text >=1.2 && <1.3 || >=2.0 && <2.2 + , text-short >=0.1.3 && <0.2 + , torsor >=0.1 && <0.2 + , vector >=0.11 && <0.14 + if os(windows) - build-depends: Win32 >= 2.2 && < 2.14 - default-language: Haskell2010 - c-sources: src/cbits/hs-time.c - ghc-options: - -Wall - -O2 + build-depends: Win32 >=2.2 && <2.14 + + c-sources: src/cbits/hs-time.c + ghc-options: -O2 test-suite chronos-test - type: exitcode-stdio-1.0 + import: build-settings + type: exitcode-stdio-1.0 hs-source-dirs: test - main-is: Spec.hs + main-is: Spec.hs build-depends: - , HUnit - , QuickCheck - , aeson >= 1.1 && < 2.2 + , aeson >=1.1 && <2.3 , attoparsec , base , bytestring , chronos - , deepseq >= 1.4.4.0 + , HUnit + , QuickCheck , test-framework , test-framework-hunit , test-framework-quickcheck2 , text , torsor - ghc-options: - -threaded - -rtsopts -with-rtsopts=-N - default-language: Haskell2010 + + ghc-options: -threaded -rtsopts -with-rtsopts=-N benchmark bench - type: exitcode-stdio-1.0 + import: build-settings + type: exitcode-stdio-1.0 hs-source-dirs: bench - main-is: Bench.hs + main-is: Bench.hs build-depends: - , QuickCheck , attoparsec , base , bytestring , chronos , criterion - , deepseq - , deepseq >= 1.4.4.0 + , deepseq >=1.4.4.0 , old-locale + , QuickCheck , text , text-short , thyme , time - , vector - default-language: Haskell2010 source-repository head - type: git + type: git location: https://github.com/andrewthad/chronos diff --git a/test/Spec.hs b/test/Spec.hs index 7da16b7..6fc736f 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -4,6 +4,7 @@ {-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -Wno-orphans #-} module Main (main) where @@ -11,13 +12,12 @@ import Chronos.Types import qualified Data.Aeson as AE import Data.ByteString (ByteString) import Data.Int (Int64) -import Data.List (intercalate) import Data.Text (Text) import Data.Text.Lazy.Builder (Builder) -import Test.Framework (defaultMain,defaultMainWithOpts,testGroup,Test) +import Test.Framework (defaultMainWithOpts,testGroup,Test) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.HUnit (Assertion,(@?=),assertBool) -import Test.QuickCheck (Gen,Arbitrary(..),discard,genericShrink,elements,suchThat) +import Test.QuickCheck (Arbitrary(..),discard,genericShrink,elements,suchThat) import Test.QuickCheck (choose,chooseInt,arbitraryBoundedEnum) import Test.QuickCheck.Property (failed,succeeded,Result(..)) import qualified Chronos as C @@ -25,7 +25,6 @@ import qualified Data.Attoparsec.ByteString as AttoBS import qualified Data.Attoparsec.Text as Atto import qualified Data.ByteString.Builder as BBuilder import qualified Data.ByteString.Lazy as LByteString -import qualified Data.Text as Text import qualified Data.Text.Lazy as LText import qualified Data.Text.Lazy.Builder as Builder import qualified Test.Framework as TF @@ -431,9 +430,9 @@ tests = [ PH.testCase "Epoch" $ C.timeToDatetime (Time 0) @?= Datetime (Date (Year 1970) C.january (DayOfMonth 1)) (TimeOfDay 0 0 0) - , PH.testCase "Billion Seconds" $ C.timeToDatetime (Time $ 10 ^ 18) + , PH.testCase "Billion Seconds" $ C.timeToDatetime (Time $ 10 ^ (18 :: Integer)) @?= Datetime (Date (Year 2001) C.september (DayOfMonth 9)) - (TimeOfDay 1 46 (40 * 10 ^ 9)) + (TimeOfDay 1 46 (40 * 10 ^ (9 :: Integer))) , testProperty "Isomorphism" $ propEncodeDecodeFullIso C.timeToDatetime C.datetimeToTime ] ] @@ -619,8 +618,8 @@ propWithinOutsideInterval (RelatedTimes t ti@(TimeInterval t0 t1)) | t < (Time 0) = discard | otherwise = let - span = C.timeIntervalToTimespan ti - tm = T.add span t + span' = C.timeIntervalToTimespan ti + tm = T.add span' t in not $ C.within tm ti @@ -630,8 +629,8 @@ propEncodeDecodeTimeInterval ti@(TimeInterval t0 t1) | t0 >= t1 = discard | otherwise = let - span = C.timeIntervalToTimespan ti - tm = T.add span t0 + span' = C.timeIntervalToTimespan ti + tm = T.add span' t0 in t1 == tm