packages feed

chronos 1.0.3 → 1.0.4

raw patch · 5 files changed

+203/−17 lines, 5 filesdep +criteriondep +deepseqdep +old-localedep ~aesondep ~attoparsecdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: criterion, deepseq, old-locale, thyme, time

Dependency ranges changed: aeson, attoparsec, base, bytestring, vector

API changes (from Hackage documentation)

- Chronos: instance Data.Semigroup.Semigroup Chronos.Timespan
+ Chronos: instance GHC.Base.Semigroup Chronos.Timespan
+ Chronos: zeptoUtf8_HMS :: Maybe Char -> Parser TimeOfDay
+ Chronos: zeptoUtf8_YmdHMS :: DatetimeFormat -> Parser Datetime

Files

+ bench/Bench.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE BangPatterns #-}++module Main where++import qualified Data.Vector.Unboxed as UVector+import Criterion.Main+import Data.Int+import Data.Maybe (fromMaybe)+import Control.DeepSeq (($!!), NFData(..), deepseq)+import qualified Data.ByteString.Char8 as BS8+import Test.QuickCheck (arbitrary, generate)+import Data.Attoparsec.ByteString.Char8 (Parser, parseOnly, char)+import qualified Data.Attoparsec.Zepto as Z+import Data.Foldable (traverse_)+import Data.Word+import Control.Monad (when)+import Control.Applicative++import qualified Data.Time as Time+import qualified Data.Thyme as Thyme+import qualified System.Locale as Thyme+import qualified Chronos++main :: IO ()+main = do+  utcthyme <- generate arbitrary :: IO Thyme.UTCTime+  let+    isoFormatString = "%Y-%m-%dT%H:%M:%S"+    renderIsoTime = Thyme.formatTime Thyme.defaultTimeLocale isoFormatString+    timeParser :: String -> Time.UTCTime+    timeParser =+      fromMaybe (error "Failed to parse in timeParser")+      . Time.parseTimeM True Time.defaultTimeLocale isoFormatString+    thymeParser :: String -> Thyme.UTCTime+    thymeParser =+      fromMaybe (error "Failed to parse in thymeParser")+      . Thyme.parseTime Thyme.defaultTimeLocale isoFormatString+    thymeAttoparsec :: BS8.ByteString -> Thyme.UTCTime+    thymeAttoparsec =+      Thyme.buildTime @Thyme.UTCTime+      . either error id+      . parseOnly (Thyme.timeParser Thyme.defaultTimeLocale isoFormatString)+    chronosAttoparsec :: BS8.ByteString -> Chronos.Datetime+    chronosAttoparsec =+      either error id+      . parseOnly (Chronos.parserUtf8_YmdHMS Chronos.w3c)+    chronosZepto :: BS8.ByteString -> Chronos.Datetime+    chronosZepto =+      either error id+      . Z.parse (Chronos.zeptoUtf8_YmdHMS Chronos.w3c)+++  string <- return $!! renderIsoTime utcthyme+  bytestring <- return $!! BS8.pack (renderIsoTime utcthyme)++  defaultMain+    [ bgroup "parsing"+      [ bench "Time.parseTimeM"           $ nf timeParser        string+      , bench "Thyme.parseTime"           $ nf thymeParser       string+      , bench "Thyme.timeParser"          $ nf thymeAttoparsec   bytestring+      , bench "Chronos.parserUtf8_YmdHMS" $ nf chronosAttoparsec bytestring+      , bench "Chronos.zeptoUtf8_YmdHMS"  $ nf chronosZepto      bytestring+      ]+    ]++instance NFData Chronos.Datetime where+  rnf (Chronos.Datetime a b) = a `deepseq` b `deepseq` ()++instance NFData Chronos.Date where+  rnf (Chronos.Date y m d) = y `deepseq` m `deepseq` d `deepseq` ()++instance NFData Chronos.TimeOfDay where+  rnf (Chronos.TimeOfDay h m s) = h `deepseq` m `deepseq` s `deepseq` ()++deriving instance NFData Chronos.DayOfMonth+deriving instance NFData Chronos.Month+deriving instance NFData Chronos.Year+deriving instance NFData Chronos.Day
chronos.cabal view
@@ -1,5 +1,5 @@ name: chronos-version: 1.0.3+version: 1.0.4 synopsis: A performant time library description:   Performance-oriented time library for haskell. The main differences@@ -73,6 +73,24 @@     , HUnit     , test-framework-hunit   ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++benchmark bench+  type:                exitcode-stdio-1.0+  hs-source-dirs:      bench+  main-is:             Bench.hs+  build-depends:+      base+    , attoparsec+    , bytestring+    , chronos+    , criterion+    , deepseq+    , old-locale+    , QuickCheck+    , thyme+    , time+    , vector   default-language:    Haskell2010  source-repository head
src/Chronos.hs view
@@ -106,6 +106,7 @@   , builderUtf8_IMSp   , parserUtf8_HMS   , parserUtf8_HMS_opt_S+  , zeptoUtf8_HMS     -- ** Datetime     -- *** Text   , builder_DmyHMS@@ -138,6 +139,7 @@   , decodeUtf8_YmdHMS_opt_S   , parserUtf8_YmdHMS   , parserUtf8_YmdHMS_opt_S+  , zeptoUtf8_YmdHMS     -- ** Offset Datetime     -- *** Text   , encode_YmdHMSz@@ -167,8 +169,8 @@   , parserOffsetUtf8     -- ** Timespan     -- *** Text-  , encodeTimespan -  , builderTimespan +  , encodeTimespan+  , builderTimespan     -- *** UTF-8 ByteString   , encodeTimespanUtf8   , builderTimespanUtf8@@ -209,7 +211,7 @@ import Data.ByteString (ByteString) import Torsor (add,difference,scale,plus) import Chronos.Internal.CTimespec (getPosixNanoseconds)-import Data.Word (Word64)+import Data.Word (Word64, Word8) import Torsor import GHC.Generics (Generic) import Data.Aeson (FromJSON,ToJSON,FromJSONKey,ToJSONKey)@@ -222,6 +224,7 @@ import qualified Data.Aeson.Types as AET import qualified Data.Attoparsec.ByteString.Char8 as AB import qualified Data.Attoparsec.Text as AT+import qualified Data.Attoparsec.Zepto as Z import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as LB@@ -273,7 +276,7 @@ offsetDatetimeToTime :: OffsetDatetime -> Time offsetDatetimeToTime = fromUtc . offsetDatetimeToUtcTime --- | Convert 'Time' to 'Day'. This function is lossy; consequently, it +-- | Convert 'Time' to 'Day'. This function is lossy; consequently, it --   does not roundtrip with 'dayToTimeMidnight'. timeToDayTruncate :: Time -> Day timeToDayTruncate (Time i) = Day (fromIntegral (div i 86400000000000) + 40587)@@ -544,7 +547,7 @@   year = quadcent * 400 + cent * 100 + quad * 4 + y + 1  {- $format- + The formats provided is this module are language-agnostic. To find meridiem formats and month formats, look in a language-specific module.@@ -747,7 +750,6 @@   when (d < 1 || d > 31) (fail "day must be between 1 and 31")   return (Date (Year y) (Month $ m - 1) (DayOfMonth d)) - builder_HMS :: SubsecondPrecision -> Maybe Char -> TimeOfDay -> TB.Builder builder_HMS sp msep (TimeOfDay h m ns) =      indexTwoDigitTextBuilder h@@ -907,7 +909,7 @@   LT.toStrict . TB.toLazyText . builderTimespan sp  builderTimespan :: SubsecondPrecision -> Timespan -> TB.Builder-builderTimespan sp (Timespan ns) = +builderTimespan sp (Timespan ns) =   TB.decimal sInt64 <> prettyNanosecondsBuilder sp nsRemainder   where   (!sInt64,!nsRemainder) = quotRem ns 1000000000@@ -931,7 +933,7 @@   builder_DmyHMS :: SubsecondPrecision -> DatetimeFormat -> Datetime -> TB.Builder-builder_DmyHMS sp (DatetimeFormat mdateSep msep mtimeSep) (Datetime date time) = +builder_DmyHMS sp (DatetimeFormat mdateSep msep mtimeSep) (Datetime date time) =   case msep of     Nothing -> builder_Dmy mdateSep date             <> builder_HMS sp mtimeSep time@@ -953,7 +955,7 @@   encode_DmyHMS :: SubsecondPrecision -> DatetimeFormat -> Datetime -> Text-encode_DmyHMS sp format = +encode_DmyHMS sp format =   LT.toStrict . TB.toLazyText . builder_DmyHMS sp format  encode_DmyIMS_p :: MeridiemLocale Text -> SubsecondPrecision -> DatetimeFormat -> Datetime -> Text@@ -1200,7 +1202,7 @@   LB.toStrict . BB.toLazyByteString . builderTimespanUtf8 sp  builderTimespanUtf8 :: SubsecondPrecision -> Timespan -> BB.Builder-builderTimespanUtf8 sp (Timespan ns) = +builderTimespanUtf8 sp (Timespan ns) =   int64Builder sInt64 <> prettyNanosecondsBuilderUtf8 sp nsRemainder   where   (!sInt64,!nsRemainder) = quotRem ns 1000000000@@ -1299,7 +1301,7 @@     LT.toStrict . TB.toLazyText . builder_YmdHMSz offsetFormat sp datetimeFormat  builder_DmyHMSz :: OffsetFormat -> SubsecondPrecision -> DatetimeFormat -> OffsetDatetime -> TB.Builder-builder_DmyHMSz offsetFormat sp datetimeFormat (OffsetDatetime datetime offset) = +builder_DmyHMSz offsetFormat sp datetimeFormat (OffsetDatetime datetime offset) =      builder_DmyHMS sp datetimeFormat datetime   <> builderOffset offsetFormat offset @@ -1309,7 +1311,7 @@   <*> parserOffset offsetFormat  builder_DmyIMS_p_z :: OffsetFormat -> MeridiemLocale Text -> SubsecondPrecision -> DatetimeFormat -> OffsetDatetime -> TB.Builder-builder_DmyIMS_p_z offsetFormat meridiemLocale sp datetimeFormat (OffsetDatetime datetime offset) = +builder_DmyIMS_p_z offsetFormat meridiemLocale sp datetimeFormat (OffsetDatetime datetime offset) =       builder_DmyIMS_p meridiemLocale sp datetimeFormat datetime    <> " "    <> builderOffset offsetFormat offset@@ -1592,6 +1594,83 @@           <> ":"           <> indexTwoDigitByteStringBuilder b +-- Zepto parsers++zeptoUtf8_YmdHMS :: DatetimeFormat -> Z.Parser Datetime+zeptoUtf8_YmdHMS (DatetimeFormat mdateSep msep' mtimeSep) = do+  date <- zeptoUtf8_Ymd mdateSep+  let msep = BC.singleton <$> msep'+  traverse_ Z.string msep+  time <- zeptoUtf8_HMS mtimeSep+  return (Datetime date time)++zeptoCountZeroes :: Z.Parser Int+zeptoCountZeroes = do+  bs <- Z.takeWhile (0x30 ==)+  pure $! BC.length bs++zeptoUtf8_Ymd :: Maybe Char -> Z.Parser Chronos.Date+zeptoUtf8_Ymd msep' = do+  y <- zeptoFixedDigitsIntBS 4+  let msep = BC.singleton <$> msep'+  traverse_ Z.string msep+  m <- zeptoFixedDigitsIntBS 2+  when (m < 1 || m > 12) (fail "month must be between 1 and 12")+  traverse_ Z.string msep+  d <- zeptoFixedDigitsIntBS 2+  when (d < 1 || d > 31) (fail "day must be between 1 and 31")+  return (Date (Year y) (Month $ m - 1) (DayOfMonth d))++zeptoUtf8_HMS :: Maybe Char -> Z.Parser Chronos.TimeOfDay+zeptoUtf8_HMS msep' = do+  h <- zeptoFixedDigitsIntBS 2+  when (h > 23) (fail "hour must be between 0 and 23")+  let msep = BC.singleton <$> msep'+  traverse_ Z.string msep+  m <- zeptoFixedDigitsIntBS 2+  when (m > 59) (fail "minute must be between 0 and 59")+  traverse_ Z.string msep+  ns <- zeptoSecondsAndNanosecondsUtf8+  return (TimeOfDay h m ns)++zeptoFixedDigitsIntBS :: Int -> Z.Parser Int+zeptoFixedDigitsIntBS n = do+  t <- Z.take n+  case BC.readInt t of+    Nothing -> fail "datetime decoding could not parse integral bytestring (a)"+    Just (i,r) -> if BC.null r+      then return i+      else fail "datetime decoding could not parse integral bytestring (b)"++zeptoSecondsAndNanosecondsUtf8 :: Z.Parser Int64+zeptoSecondsAndNanosecondsUtf8 = do+  s' <- zeptoFixedDigitsIntBS 2+  let s = fromIntegral s' :: Int64+  when (s > 60) (fail "seconds must be between 0 and 60")+  nanoseconds <-+    ( do _ <- Z.string "."+         numberOfZeroes <- zeptoCountZeroes+         x <- zdecimal+         let totalDigits = countDigits x + numberOfZeroes+             result = if totalDigits == 9+               then x+               else if totalDigits < 9+                 then x * raiseTenTo (9 - totalDigits)+                 else quot x (raiseTenTo (totalDigits - 9))+         return (fromIntegral result)+    ) <|> return 0+  return (s * 1000000000 + nanoseconds)++zdecimal :: Z.Parser Int64+zdecimal = do+  digits <- Z.takeWhile wordIsDigit+  case BC.readInt digits of+    Nothing -> fail "somehow this didn't work"+    Just (i,_) -> pure $! fromIntegral i++wordIsDigit :: Word8 -> Bool+wordIsDigit a = 0x30 <= a && a <= 0x39+ january :: Month january = Month 0 @@ -2087,4 +2166,3 @@ aesonParserOffset t = case decodeOffset OffsetFormatColonOn t of   Nothing -> fail "could not parse Offset"   Just x -> return x-
src/Chronos/Internal/CTimespec.hs view
@@ -51,6 +51,3 @@   return ((s * 1000000000) + ns)  #endif---
src/cbits/hs-time.c view
@@ -1,5 +1,10 @@ #ifdef __MACH__+#include <Availability.h> #include <sys/time.h>++#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED++#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1012 //clock_gettime is not implemented on OSX int clock_gettime(int clk_id, struct timespec* t) {   struct timeval now;@@ -9,4 +14,9 @@   t->tv_nsec = now.tv_usec * 1000;   return 0; }+#else+#endif++#endif+ #endif