chronologique 0.3.0.1 → 0.3.1.1
raw patch · 4 files changed
+89/−23 lines, 4 filesdep +aesondep +bytestringdep +textPVP ok
version bump matches the API change (PVP)
Dependencies added: aeson, bytestring, text
API changes (from Hackage documentation)
+ Chrono.TimeStamp: instance Data.Aeson.Types.FromJSON.FromJSON Chrono.TimeStamp.TimeStamp
+ Chrono.TimeStamp: instance Data.Aeson.Types.ToJSON.ToJSON Chrono.TimeStamp.TimeStamp
+ Chrono.TimeStamp: instance GHC.Generics.Generic Chrono.TimeStamp.TimeStamp
Files
- chronologique.cabal +6/−2
- lib/Chrono/TimeStamp.hs +44/−16
- tests/CheckTimeStamp.hs +19/−3
- tests/Experiment.hs +20/−2
chronologique.cabal view
@@ -1,6 +1,6 @@ cabal-version: >= 1.10 name: chronologique-version: 0.3.0.1+version: 0.3.1.1 synopsis: Time to manipulate time description: A simple type useful for representing timestamps as generated by system@@ -35,7 +35,9 @@ build-depends: base >= 4.9 && < 5, time, hourglass,- vector+ vector,+ text,+ aeson hs-source-dirs: lib @@ -74,6 +76,8 @@ hourglass, QuickCheck, vector,+ bytestring,+ aeson, chronologique hs-source-dirs: tests
lib/Chrono/TimeStamp.hs view
@@ -9,6 +9,7 @@ -- the 3-clause BSD licence. -- +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE TupleSections #-}@@ -25,12 +26,17 @@ ) where import Control.Applicative+import Data.Aeson+import Data.Aeson.Types (typeMismatch)+import Data.Aeson.Encoding (string) import Data.Maybe import Data.Int (Int64) import Data.Hourglass+import qualified Data.Text as T import qualified Data.Vector.Generic as G import qualified Data.Vector.Generic.Mutable as M import Data.Vector.Unboxed+import GHC.Generics import Time.System import Chrono.Formats@@ -78,7 +84,7 @@ -- newtype TimeStamp = TimeStamp { unTimeStamp :: Int64-} deriving (Eq, Ord, Enum, Num, Real, Integral, Bounded)+} deriving (Eq, Ord, Enum, Num, Real, Integral, Bounded, Generic) {- Hourglass works by sending types in and out of the Timeable and Time@@ -105,25 +111,28 @@ instance Show TimeStamp where- show t =- timePrint ISO8601_Precise t+ 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+ readsPrec _ s = maybeToList $ (,"") <$> parseInput s -reduceDateTime :: DateTime -> TimeStamp-reduceDateTime = timeFromElapsedP . timeGetElapsedP+parseInput :: String -> Maybe TimeStamp+parseInput = fmap reduceDateTime . parse+ 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).@@ -176,4 +185,23 @@ {-# INLINE basicUnsafeWrite #-} deriving instance Unbox TimeStamp++{-+ JSON encoding and decoding+-}++instance ToJSON TimeStamp where+ toEncoding = string . timePrint ISO8601_Precise++instance FromJSON TimeStamp where+ parseJSON (String value) =+ let+ str = T.unpack value+ result = parseInput str+ in+ case result of+ Just t -> pure t+ Nothing -> fail "Unable to parse input as a TimeStamp"++ parseJSON (invalid) = typeMismatch "TimeStamp" invalid
tests/CheckTimeStamp.hs view
@@ -17,6 +17,8 @@ module CheckTimeStamp where +import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as L import Test.Hspec import Test.QuickCheck import Data.Hourglass@@ -102,13 +104,27 @@ show (convertToUTC t) `shouldBe` "2014-07-31 23:23:35.948797001 UTC" it "behaves when QuickChecked" $ do- property prop_RoundTrip+ property prop_RoundTrip_ReadShow + describe "Round trip via JSON" $ do+ it "explicit JSON encoding is correct" $ do+ let t = read "2018-05-01T01:42:12Z" :: TimeStamp+ encode t `shouldBe` L.pack "\"2018-05-01T01:42:12.000000000Z\"" + it "converts to a JSON String and back again" $ do+ let t = read "2018-05-01T01:42:12Z" :: TimeStamp+ (decode . encode) t `shouldBe` Just t++ it "behaves when QuickChecked" $ do+ property prop_RoundTrip_Aeson+ instance Arbitrary TimeStamp where arbitrary = do tick <- arbitrary return (TimeStamp tick) -prop_RoundTrip :: TimeStamp -> Bool-prop_RoundTrip t = (read . show) t == t+prop_RoundTrip_ReadShow :: TimeStamp -> Bool+prop_RoundTrip_ReadShow t = (read . show) t == t++prop_RoundTrip_Aeson :: TimeStamp -> Bool+prop_RoundTrip_Aeson t = (decode . encode) t == Just t
tests/Experiment.hs view
@@ -4,8 +4,26 @@ module Main where import Chrono.TimeStamp+import Data.Aeson+import Data.ByteString.Builder+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.Text.IO as T+import System.IO +x :: L.ByteString+x = "2018-05-01T01:42:12Z"+t = read (L.unpack x) :: TimeStamp+j = toEncoding t+ main :: IO () main = do- putStrLn "Hello"- + putStrLn . show . unTimeStamp $ t+ putStrLn . show . toJSON $ t+ L.putStrLn . toLazyByteString . fromEncoding . toEncoding $ t+ L.putStrLn . encode $ t++ putStrLn . show . (decode :: L.ByteString -> Maybe TimeStamp) . encode $ t+ putStrLn . show . (eitherDecode :: L.ByteString -> Either String TimeStamp) $ "234"+ putStrLn . show . (eitherDecode :: L.ByteString -> Either String TimeStamp) $ L.concat ["\"", x, "\""]+ putStrLn . show . (eitherDecode :: L.ByteString -> Either String TimeStamp) $ L.concat ["\"", "2018-05:01T01:42:12Z" , "\""]+