packages feed

chronologique (empty) → 0.2.1.0

raw patch · 8 files changed

+580/−0 lines, 8 filesdep +QuickCheckdep +basedep +chronologique

Dependencies added: QuickCheck, base, chronologique, hourglass, hspec, time

Files

+ LICENCE view
@@ -0,0 +1,32 @@+Time to manipulate time++Copyright © 2013-2017 Operational Dynamics Consulting, Pty Ltd and Others+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++    1. Redistributions of source code must retain the above copyright+       notice, this list of conditions and the following disclaimer.++    2. Redistributions in binary form must reproduce the above+       copyright notice, this list of conditions and the following+       disclaimer in the documentation and/or other materials provided+       with the distribution.+      +    3. Neither the name of the project nor the names of its contributors+       may be used to endorse or promote products derived from this +       software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ chronologique.cabal view
@@ -0,0 +1,88 @@+cabal-version:       >= 1.10+name:                chronologique+version:             0.2.1.0+synopsis:            Time to manipulate time+description:+ A simple type useful for representing timestamps as generated by system+ events, along with conveniences for converting between time types from common+ Haskell time libraries.+ .+ Our original use was wanting to conveniently measure things happening on+ distributed computer systems. Since machine clock cycles are in units of+ nanoseconds, this has the nice property that, assuming the system clock is not+ corrupted, two subsequent events from the same source process are likely to+ have monotonically increasing timestamps. And even if the system clock has+ skew, they're still decently likely to be unique per device. These TimeStamps+ thus make good keys when building Maps.+ .+ The core type is in "Chrono.TimeStamp", see there for full documentation.++license:             BSD3+license-file:        LICENCE+author:              Andrew Cowie <andrew@operationaldynamics.com>+maintainer:          Andrew Cowie <andrew@operationaldynamics.com>+copyright:           © 2016-2017 Operational Dynamics Consulting Pty Ltd, and Others+category:            Text+tested-with:         GHC == 8.0++build-type:          Simple++library+  default-language:  Haskell2010++  build-depends:     base >= 4.9 && < 5,+                     time,+                     hourglass++  hs-source-dirs:    lib++  exposed-modules:   Chrono.TimeStamp+                     Chrono.Compat+  other-modules:     Chrono.Formats++  ghc-options:       -Wall+                     -Wwarn+                     -fwarn-tabs++test-suite           experiment+  type:              exitcode-stdio-1.0+  default-language:  Haskell2010+  buildable:         False++  build-depends:     base,+                     chronologique++  hs-source-dirs:    tests++  main-is:           Experiment.hs++  ghc-options:       -threaded+                     -O2+                     -Wall+                     -Wwarn+                     -fwarn-tabs+++test-suite           check+  type:              exitcode-stdio-1.0+  default-language:  Haskell2010++  build-depends:     base,+                     hspec,+                     hourglass,+                     QuickCheck,+                     chronologique++  hs-source-dirs:    tests++  main-is:           TestSuite.hs++  other-modules:     CheckTimeStamp++  ghc-options:       -threaded+                     -O2+                     -Wall+                     -Wwarn+                     -fwarn-tabs++-- vim: set tabstop=22 expandtab:
+ lib/Chrono/Compat.hs view
@@ -0,0 +1,73 @@+--+-- Time to manipulate time+--+-- Copyright © 2013-2016 Operational Dynamics Consulting, Pty Ltd and Others+--+-- The code in this file, and the program it is a part of, is+-- made available to you by its authors as open source software:+-- you can redistribute it and/or modify it under the terms of+-- the 3-clause BSD licence.+--++--+-- | Compatibility with time types from other time handling libraries. Some of+-- these are just conveniences, but it's not always obvious how to convert+-- between time types even in the same package.+--+module Chrono.Compat+(+  -- * time package, from base+    convertToPosix+  , convertFromPosix+  , convertToUTC+  , convertFromUTC+  -- * hourglass package+  , convertToHourglass+  , convertFromHourglass+) where++import Data.Int (Int64)+import Data.Hourglass+import Data.Time.Clock+import Data.Time.Clock.POSIX++import Chrono.TimeStamp++--+-- | Utility function to convert nanoseconds since Unix epoch to a+-- 'NominalDiffTime', allowing you to then use the time manipulation+-- functions in "Data.Time.Clock" from __time__.+--+convertToPosix :: TimeStamp -> POSIXTime+convertToPosix = fromRational . (/ 1e9) . fromIntegral++--+--+-- | Utility function to convert nanoseconds since Unix epoch to a+-- 'ElapsedP', allowing you to then use the time manipulation+-- functions in the __hourglass__ package.+--+convertToHourglass :: TimeStamp -> ElapsedP+convertToHourglass = timeGetElapsedP++convertFromHourglass :: ElapsedP -> TimeStamp+convertFromHourglass = timeFromElapsedP+++--+-- | Annoyingly, the various types in __time__ don't interoperate. Quite frequently+-- you need to get to, or from, 'UTCTime'.+--+convertToUTC :: TimeStamp -> UTCTime+convertToUTC = posixSecondsToUTCTime . convertToPosix++convertFromUTC :: UTCTime -> TimeStamp+convertFromUTC = convertFromPosix . utcTimeToPOSIXSeconds++convertFromPosix :: POSIXTime -> TimeStamp+convertFromPosix =+  let+    nano :: POSIXTime -> Int64+    nano = floor . (* 1000000000) . toRational+  in+    TimeStamp . fromIntegral . nano
+ lib/Chrono/Formats.hs view
@@ -0,0 +1,116 @@+--+-- Time to manipulate time+--+-- Copyright © 2013-2016 Operational Dynamics Consulting, Pty Ltd and Others+--+-- The code in this file, and the program it is a part of, is+-- made available to you by its authors as open source software:+-- you can redistribute it and/or modify it under the terms of+-- the 3-clause BSD licence.+--++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Chrono.Formats+(+    ISO8601_Precise(..)+  , ISO8601_Seconds(..)+  , ISO8601_Days(..)+  , Posix_Precise(..)+  , Posix_Micro(..)+  , Posix_Milli(..)+  , Posix_Seconds(..)+) where++import Data.Hourglass++--+-- | Format string describing full (nanosecond) precision ISO8601 time,+--+-- > 2014-07-31T23:09:35.274387019Z+--+data ISO8601_Precise = ISO8601_Precise++instance TimeFormat ISO8601_Precise where+    toFormat _ = TimeFormatString+        [ Format_Year+        , Format_Text '-'+        , Format_Month2+        , Format_Text '-'+        , Format_Day2+        , Format_Text 'T'+        , Format_Hour+        , Format_Text ':'+        , Format_Minute+        , Format_Text ':'+        , Format_Second+        , Format_Text '.'+        , Format_Precision 9+        , Format_Text 'Z'+        ]++data ISO8601_Seconds = ISO8601_Seconds++instance TimeFormat ISO8601_Seconds where+    toFormat _ = TimeFormatString+        [ Format_Year+        , Format_Text '-'+        , Format_Month2+        , Format_Text '-'+        , Format_Day2+        , Format_Text 'T'+        , Format_Hour+        , Format_Text ':'+        , Format_Minute+        , Format_Text ':'+        , Format_Second+        , Format_Text 'Z'+        ]++data ISO8601_Days = ISO8601_Days++instance TimeFormat ISO8601_Days where+    toFormat _ = TimeFormatString+        [ Format_Year+        , Format_Text '-'+        , Format_Month2+        , Format_Text '-'+        , Format_Day2+        ]++data Posix_Precise = Posix_Precise++instance TimeFormat Posix_Precise where+    toFormat _ = TimeFormatString+        [ Format_UnixSecond+        , Format_Text '.'+        , Format_MilliSecond+        , Format_MicroSecond+        , Format_NanoSecond+        ]++data Posix_Micro = Posix_Micro++instance TimeFormat Posix_Micro where+    toFormat _ = TimeFormatString+        [ Format_UnixSecond+        , Format_Text '.'+        , Format_MilliSecond+        , Format_MicroSecond+        ]++data Posix_Milli = Posix_Milli++instance TimeFormat Posix_Milli where+    toFormat _ = TimeFormatString+        [ Format_UnixSecond+        , Format_Text '.'+        , Format_MilliSecond+        ]++data Posix_Seconds = Posix_Seconds++instance TimeFormat Posix_Seconds where+    toFormat _ = TimeFormatString+        [ Format_UnixSecond+        ]
+ lib/Chrono/TimeStamp.hs view
@@ -0,0 +1,131 @@+--+-- Time to manipulate time+--+-- Copyright © 2013-2016 Operational Dynamics Consulting, Pty Ltd and Others+--+-- The code in this file, and the program it is a part of, is+-- made available to you by its authors as open source software:+-- you can redistribute it and/or modify it under the terms of+-- the 3-clause BSD licence.+--++{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE TupleSections #-}++module Chrono.TimeStamp+(+    TimeStamp(..)+  , getCurrentTimeNanoseconds++  , ISO8601_Precise(..)+) where++import Control.Applicative+import Data.Maybe+import Data.Int (Int64)+import Data.Hourglass+import Time.System++import Chrono.Formats++--+-- | Number of nanoseconds since the Unix epoch.+--+-- The Show instance displays the TimeStamp as seconds with the nanosecond+-- precision expressed as a decimal amount after the interger, ie:+--+-- >>> t <- getCurrentTimeNanoseconds+-- >>> show t+-- 2014-07-31T23:09:35.274387031Z+--+-- However this doesn't change the fact the underlying representation counts+-- nanoseconds since epoch:+--+-- >>> show $ unTimeStamp t+-- 1406848175274387031+--+-- There is a Read instance that is reasonably accommodating.+--+-- >>> read "2014-07-31T13:05:04.942089001Z" :: TimeStamp+-- 2014-07-31T13:05:04.942089001Z+--+-- >>> read "1406811904.942089001" :: TimeStamp+-- 2014-07-31T13:05:04.942089001Z+--+-- >>> read "1406811904" :: TimeStamp+-- 2014-07-31T13:05:04.000000000Z+--+-- In case you're wondering, the valid range of nanoseconds that fits into the+-- underlying Int64 is:+--+-- >>> show $ minBound :: TimeStamp+-- 1677-09-21T00:12:43.145224192Z+--+-- >>> show $ maxBound :: TimeStamp+-- 2262-04-11T23:47:16.854775807Z+--+-- so in a quarter millenium's time, yes, you'll have the Y2262 Problem.+-- Haskell code from today will, of course, still be running, so in the mid+-- Twenty-Third century you will need to replace this implementation with+-- something else.+--+newtype TimeStamp = TimeStamp {+    unTimeStamp :: Int64+} deriving (Eq, Ord, Enum, Num, Real, Integral, Bounded)++{-+    Hourglass works by sending types in and out of the Timeable and Time+    typeclasses. They're not particularly easy to work with, but they're a+    prerequisite for using timePrint+-}++instance Timeable TimeStamp where+    timeGetElapsedP :: TimeStamp -> ElapsedP+    timeGetElapsedP (TimeStamp ticks) =+      let+        (s,ns) = divMod ticks 1000000000+      in+        ElapsedP (Elapsed (Seconds (s))) (NanoSeconds (ns))++instance Time TimeStamp where+    timeFromElapsedP :: ElapsedP -> TimeStamp+    timeFromElapsedP (ElapsedP (Elapsed (Seconds seconds)) (NanoSeconds nanoseconds)) =+      let+        s  = fromIntegral seconds :: Int64+        ns = fromIntegral nanoseconds+      in+        TimeStamp $! (s * 1000000000) + ns+++instance Show TimeStamp where+    show t =+        timePrint ISO8601_Precise t++instance Read TimeStamp where+    readsPrec _ s = maybeToList $ (,"") <$> reduceDateTime <$> parse s+      where+        parse :: String -> Maybe DateTime+        parse x =   timeParse ISO8601_Precise x+                <|> timeParse ISO8601_Seconds x+                <|> timeParse ISO8601_DateAndTime x -- from hourglass+                <|> timeParse ISO8601_Date x        -- from hourglass+                <|> timeParse Posix_Precise x+                <|> timeParse Posix_Micro x+                <|> timeParse Posix_Milli x+                <|> timeParse Posix_Seconds x++reduceDateTime :: DateTime -> TimeStamp+reduceDateTime = timeFromElapsedP . timeGetElapsedP++--+-- | Get the current system time, expressed as a 'TimeStamp' (which is to+-- say, number of nanoseconds since the Unix epoch).+--+getCurrentTimeNanoseconds :: IO TimeStamp+getCurrentTimeNanoseconds = do+    p <- timeCurrentP+    return $! convertToTimeStamp p++convertToTimeStamp :: ElapsedP -> TimeStamp+convertToTimeStamp = timeFromElapsedP
+ tests/CheckTimeStamp.hs view
@@ -0,0 +1,114 @@+--+-- Time to manipulate time+--+-- Copyright © 2013-2016 Operational Dynamics Consulting, Pty Ltd and Others+--+-- The code in this file, and the program it is a part of, is+-- made available to you by its authors as open source software:+-- you can redistribute it and/or modify it under the terms of+-- the 3-clause BSD licence.+--++-- | Test serialisation/deserialiastion for TimeStamp type++{-# LANGUAGE BinaryLiterals #-}+{-# LANGUAGE NegativeLiterals #-}+{-# OPTIONS -fno-warn-orphans #-}++module CheckTimeStamp where++import Test.Hspec+import Test.QuickCheck+import Data.Hourglass++import Chrono.TimeStamp+import Chrono.Compat++checkTimeStamp :: Spec+checkTimeStamp = do+    describe "Smallest valid TimeStamp" $+      let+        t = TimeStamp (-9223372036854775808)+      in do+        it "should be representable" $ do+            t `shouldBe` (minBound :: TimeStamp)++        it "should be match when Shown" $ do+            show t `shouldBe` show (minBound :: TimeStamp)++        it "should equal expected value" $ do+            show t `shouldBe` "1677-09-21T00:12:43.145224192Z"++    describe "Largest valid TimeStamp" $+      let+        t = TimeStamp 9223372036854775807+      in do+        it "should be representable" $ do+            t `shouldBe` (maxBound :: TimeStamp)++        it "should be match when Shown" $ do+            show t `shouldBe` show (maxBound :: TimeStamp)++        it "should equal expected value" $ do+            show t `shouldBe` "2262-04-11T23:47:16.854775807Z"++    describe "Printing and parsing with precise format" $ do+        it "formats a known date correctly" $ do+            timePrint ISO8601_Precise (TimeStamp 1406849015948797001) `shouldBe` "2014-07-31T23:23:35.948797001Z"++        it "uses timeParse effectively" $ do+            timeParse ISO8601_Precise "2014-07-31T23:42:35.948797001Z" `shouldBe`+                Just (DateTime (Date 2014 July 31) (TimeOfDay 23 42 35 948797001))++    describe "Round trip through Read and Show instances" $ do+        it "outputs a correctly formated ISO 8601 timestamp when Shown" $ do+            show (TimeStamp 1406849015948797001) `shouldBe` "2014-07-31T23:23:35.948797001Z"+            show (TimeStamp 1406849015948797001) `shouldBe` "2014-07-31T23:23:35.948797001Z"+            show (TimeStamp 0) `shouldBe` "1970-01-01T00:00:00.000000000Z"++        it "Reads ISO 8601 timestamps" $ do+            read "2014-07-31T23:23:35.948797001Z" `shouldBe` TimeStamp 1406849015948797001+            read "2014-07-31T23:23:35Z" `shouldBe` TimeStamp 1406849015000000000+            read "2014-07-31" `shouldBe` TimeStamp 1406764800000000000++        it "reads the Unix epoch date" $+            read "1970-01-01" `shouldBe` TimeStamp 0++        it "permissively reads various formats" $ do+            show (read "1970-01-01T00:00:00.000000000Z" :: TimeStamp) `shouldBe` "1970-01-01T00:00:00.000000000Z"+            show (read "1970-01-01" :: TimeStamp) `shouldBe` "1970-01-01T00:00:00.000000000Z"+            show (read "0" :: TimeStamp) `shouldBe` "1970-01-01T00:00:00.000000000Z"++        it "permissively reads Posix seconds since epoch" $ do+            show (read "1406849015.948797001" :: TimeStamp) `shouldBe` "2014-07-31T23:23:35.948797001Z"+            show (read "1406849015.948797" :: TimeStamp) `shouldBe` "2014-07-31T23:23:35.948797000Z"+            show (read "1406849015.948" :: TimeStamp) `shouldBe` "2014-07-31T23:23:35.948000000Z"+            show (read "1406849015" :: TimeStamp) `shouldBe` "2014-07-31T23:23:35.000000000Z"+{-+    This is a bit fragile, depending as it does on the serialization to String+    in the Show instance of UTCTime. Not that they're going to change it+    anytime soon.+-}++    describe "Round trip through base time types" $ do+        it "converts to POSIXTime and back again" $ do+            let t = TimeStamp 1406849015948797001+            convertFromPosix (convertToPosix t) `shouldBe` t+            show (convertToPosix t) `shouldBe` "1406849015.948797001s"++        it "converts to UTCTime and back again" $ do+            let t = TimeStamp 1406849015948797001+            convertFromUTC (convertToUTC t) `shouldBe` t+            show (convertToUTC t) `shouldBe` "2014-07-31 23:23:35.948797001 UTC"++        it "behaves when QuickChecked" $ do+            property prop_RoundTrip+++instance Arbitrary TimeStamp where+    arbitrary = do+        tick <- arbitrary+        return (TimeStamp tick)++prop_RoundTrip :: TimeStamp -> Bool+prop_RoundTrip t = (read . show) t == t
+ tests/Experiment.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS -fno-warn-unused-imports #-}++module Main where++import Chrono.TimeStamp++main :: IO ()+main = do+    putStrLn "Hello"+ 
+ tests/TestSuite.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Test.Hspec++import CheckTimeStamp++main :: IO ()+main = hspec suite++suite :: Spec+suite = do+    checkTimeStamp+