packages feed

attoparsec-time 0.1.4 → 1

raw patch · 8 files changed

+767/−430 lines, 8 filesdep +bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring

API changes (from Hackage documentation)

- Attoparsec.Time: dayInISO8601 :: Parser Day
- Attoparsec.Time: diffTime :: Parser DiffTime
- Attoparsec.Time: nominalDiffTime :: Parser NominalDiffTime
- Attoparsec.Time: timeOfDayInISO8601 :: Parser TimeOfDay
- Attoparsec.Time: timeZoneInISO8601 :: Parser TimeZone
- Attoparsec.Time: utcTimeInISO8601 :: Parser UTCTime
+ Attoparsec.Time.ByteString: dayInISO8601 :: Parser Day
+ Attoparsec.Time.ByteString: diffTime :: Parser DiffTime
+ Attoparsec.Time.ByteString: nominalDiffTime :: Parser NominalDiffTime
+ Attoparsec.Time.ByteString: timeOfDayInISO8601 :: Parser TimeOfDay
+ Attoparsec.Time.ByteString: timeZoneInISO8601 :: Parser TimeZone
+ Attoparsec.Time.ByteString: utcTimeInISO8601 :: Parser UTCTime
+ Attoparsec.Time.Text: dayInISO8601 :: Parser Day
+ Attoparsec.Time.Text: diffTime :: Parser DiffTime
+ Attoparsec.Time.Text: nominalDiffTime :: Parser NominalDiffTime
+ Attoparsec.Time.Text: timeOfDayInISO8601 :: Parser TimeOfDay
+ Attoparsec.Time.Text: timeZoneInISO8601 :: Parser TimeZone
+ Attoparsec.Time.Text: utcTimeInISO8601 :: Parser UTCTime

Files

attoparsec-time.cabal view
@@ -1,7 +1,7 @@ name:   attoparsec-time version:-  0.1.4+  1 synopsis:   Attoparsec parsers of time description:@@ -25,7 +25,7 @@ build-type:   Custom cabal-version:-  >= 1.24+  >=1.10  source-repository head   type:@@ -35,7 +35,7 @@  custom-setup   setup-depends:-    base, Cabal, cabal-doctest >= 1.0.2 && < 1.1+    base, Cabal, cabal-doctest >=1.0.2 && <1.1  library   hs-source-dirs:@@ -45,21 +45,23 @@   default-language:     Haskell2010   exposed-modules:-    Attoparsec.Time+    Attoparsec.Time.ByteString+    Attoparsec.Time.Text   other-modules:     Attoparsec.Time.Prelude-    Attoparsec.Time.Validators-    Attoparsec.Time.Constructors+    Attoparsec.Time.Validation+    Attoparsec.Time.Pure   build-depends:     -- -    attoparsec >= 0.13 && < 0.15,+    attoparsec >=0.13 && <0.15,     ---    time >= 1.4 && < 2,-    scientific == 0.3.*,-    text >= 1 && < 2,+    time >=1.4 && <2,+    scientific ==0.3.*,+    text >=1 && <2,+    bytestring ==0.10.*,     ---    base-prelude < 2,-    base >= 4.7 && < 5+    base-prelude <2,+    base >=4.7 && <5  test-suite doctests   type:@@ -75,8 +77,8 @@   default-language:     Haskell2010   build-depends:-    doctest == 0.13.*,-    directory >= 1.2 && < 2,-    filepath >= 1.4 && < 2,-    base-prelude < 2,-    base < 5+    doctest ==0.13.*,+    directory >=1.2 && <2,+    filepath >=1.4 && <2,+    base-prelude <2,+    base <5
− library/Attoparsec/Time.hs
@@ -1,332 +0,0 @@-module Attoparsec.Time-(-  timeOfDayInISO8601,-  dayInISO8601,-  timeZoneInISO8601,-  utcTimeInISO8601,-  diffTime,-  nominalDiffTime,-)-where--import Attoparsec.Time.Prelude hiding (take, takeWhile)-import Data.Attoparsec.Text-import qualified Attoparsec.Time.Constructors as A-import qualified Attoparsec.Time.Validators as B-import qualified Data.Text as C---validated :: Show a => B.Validator a -> Parser a -> Parser a-validated validator parser =-  parser >>= \x -> B.run validator (pure x) fail x--sign :: Parser Bool-sign =-  anyChar >>= \case-    '+' -> return True-    '-' -> return False-    _ -> empty--decimalChar :: Parser Int-decimalChar =-  satisfyWith ((subtract 48) . ord) ((&&) <$> (>= 0) <*> (<= 9))--decimalOfLength :: Num a => Int -> Parser a-decimalOfLength length =-  foldl' (\a b -> a * 10 + b) 0 <$>-  replicateM length (fmap fromIntegral decimalChar) <|>-  fail "Invalid decimal length"--shortMonth :: Parser Int-shortMonth =-  liftM C.toLower (take 3) >>= \case-    "jan" -> return 1-    "feb" -> return 2-    "mar" -> return 3-    "apr" -> return 4-    "may" -> return 5-    "jun" -> return 6-    "jul" -> return 7-    "aug" -> return 8-    "sep" -> return 9-    "oct" -> return 10-    "nov" -> return 11-    "dec" -> return 12-    _ -> empty--picoWithBasisOfLength :: Int -> Parser Pico-picoWithBasisOfLength basisLength =-  (\a b -> MkFixed (foldl' (\a b -> a * 10 + fromIntegral b) 0 (a ++ b))) <$> beforePoint <*> afterPoint-  where-    resolution =-      12-    beforePoint =-      replicateM basisLength decimalChar-    afterPoint =-      padListFromRight 0 [] resolution <$> ((char '.' *> many decimalChar) <|> pure [])-      where-        padListFromRight padding accumulator length list =-          case length of-            0 -> reverse accumulator-            _ -> case list of-              head : tail -> padListFromRight padding (head : accumulator) (pred length) tail-              _ -> reverse accumulator ++ replicate length padding--{-# INLINE hour #-}-hour :: Parser Int-hour =-  validated B.hour (decimalOfLength 2) <?> "hour"--{-# INLINE minute #-}-minute :: Parser Int-minute =-  validated B.minute (decimalOfLength 2) <?> "minute"--{-# INLINE second #-}-second :: Parser Pico-second =-  validated B.second (picoWithBasisOfLength 2) <?> "second"--{-|->>> parseOnly timeOfDayInISO8601 "05:03:58"-Right 05:03:58-->>> parseOnly timeOfDayInISO8601 "05:03:58.02"-Right 05:03:58.02-->>> parseOnly timeOfDayInISO8601 "05:03:58.020"-Right 05:03:58.02--Checks the elements to be within a proper range:-->>> parseOnly timeOfDayInISO8601 "24:00:00"-Left "timeOfDayInISO8601 > hour: Failed reading: Validator \"hour\" failed on the following input: 24"-->>> parseOnly timeOfDayInISO8601 "00:00:60"-Left "timeOfDayInISO8601 > second: Failed reading: Validator \"second\" failed on the following input: 60.000000000000"--Checks the elements to be of proper length:-->>> parseOnly timeOfDayInISO8601 "1:00:00"-Left "timeOfDayInISO8601 > hour: Failed reading: Invalid decimal length"-->>> parseOnly timeOfDayInISO8601 "01:1:00"-Left "timeOfDayInISO8601 > minute: Failed reading: Invalid decimal length"--}-{-# INLINE timeOfDayInISO8601 #-}-timeOfDayInISO8601 :: Parser TimeOfDay-timeOfDayInISO8601 =-  unnamedParser <?> "timeOfDayInISO8601"-  where-    unnamedParser =-      A.timeOfDay <$>-      (hour <* char ':') <*>-      (minute <* char ':') <*>-      (second)--{-|->>> parseOnly dayInISO8601 "2017-02-01"-Right 2017-02-01--Checks the elements to be in proper range:-->>> parseOnly dayInISO8601 "2017-13-01"-Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,13,1)"--That is accounting for leap year:-->>> parseOnly dayInISO8601 "2017-02-29"-Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,2,29)"-->>> parseOnly dayInISO8601 "2016-02-29"-Right 2016-02-29--}-{-# INLINE dayInISO8601 #-}-dayInISO8601 :: Parser Day-dayInISO8601 =-  unnamedParser <?> "dayInISO8601"-  where-    unnamedParser =-      do-        year <- decimalOfLength 4-        char '-'-        month <- decimalOfLength 2-        char '-'-        day <- decimalOfLength 2-        case fromGregorianValid year month day of-          Just day -> return day-          Nothing -> fail (error year month day)-      where-        error year month day =-          showString "Invalid combination of year month and day: " $ -          show (year, month, day)--{-|->>> parseOnly timeZoneInISO8601 "+01:00"-Right +0100-->>> parseOnly timeZoneInISO8601 "+0100"-Right +0100-->>> parseOnly timeZoneInISO8601 "-0100"-Right -0100-->>> parseOnly timeZoneInISO8601 "Z"-Right UTC--}-timeZoneInISO8601 :: Parser TimeZone-timeZoneInISO8601 =-  unnamedParser <?> "timeZoneInISO8601"-  where-    unnamedParser =-      z <|> offset-      where-        z =-          char 'Z' $> utc-        offset =-          A.timeZone <$> sign <*> decimalOfLength 2 <*> (char ':' *> decimalOfLength 2 <|> decimalOfLength 2 <|> pure 0)--{-|->>> parseOnly utcTimeInISO8601 "2017-02-01T05:03:58+01:00"-Right 2017-02-01 04:03:58 UTC--}-utcTimeInISO8601 :: Parser UTCTime-utcTimeInISO8601 =-  unnamedParser <?> "utcTimeInISO8601"-  where-    unnamedParser =-      do-        day <- dayInISO8601-        char 'T'-        time <- timeOfDayInISO8601-        zone <- timeZoneInISO8601-        return (A.utcTimeFromDayAndTimeOfDay day time zone)--{-|-No suffix implies the "seconds" unit:-->>> parseOnly diffTime "10"-Right 10s--Various units (seconds, minutes, hours, days):-->>> parseOnly diffTime "10s"-Right 10s-->>> parseOnly diffTime "10m"-Right 600s-->>> parseOnly diffTime "10h"-Right 36000s-->>> parseOnly diffTime "10d"-Right 864000s--Metric prefixes to seconds (down to Pico):-->>> parseOnly diffTime "10ms"-Right 0.01s-->>> parseOnly diffTime "10μs"-Right 0.00001s-->>> parseOnly diffTime "10us"-Right 0.00001s-->>> parseOnly diffTime "10ns"-Right 0.00000001s-->>> parseOnly diffTime "10ps"-Right 0.00000000001s--Negative values:-->>> parseOnly diffTime "-1s"-Right -1s--Unsupported units:-->>> parseOnly diffTime "1k"-Left "diffTime: Failed reading: Unsupported unit: \"k\""--}-diffTime :: Parser DiffTime-diffTime =-  unnamedParser <?> "diffTime"-  where-    unnamedParser =-      do-        amount <- scientific-        factor <- timeUnitFactor-        return (factor (realToFrac amount))--{-|-No suffix implies the "seconds" unit:-->>> parseOnly nominalDiffTime "10"-Right 10s--Various units (seconds, minutes, hours, days):-->>> parseOnly nominalDiffTime "10s"-Right 10s-->>> parseOnly nominalDiffTime "10m"-Right 600s-->>> parseOnly nominalDiffTime "10h"-Right 36000s-->>> parseOnly nominalDiffTime "10d"-Right 864000s--Metric prefixes to seconds (down to Pico):-->>> parseOnly nominalDiffTime "10ms"-Right 0.01s-->>> parseOnly nominalDiffTime "10μs"-Right 0.00001s-->>> parseOnly nominalDiffTime "10us"-Right 0.00001s-->>> parseOnly nominalDiffTime "10ns"-Right 0.00000001s-->>> parseOnly nominalDiffTime "10ps"-Right 0.00000000001s--Negative values:-->>> parseOnly nominalDiffTime "-1s"-Right -1s--Unsupported units:-->>> parseOnly nominalDiffTime "1k"-Left "nominalDiffTime: Failed reading: Unsupported unit: \"k\""--}-nominalDiffTime :: Parser NominalDiffTime-nominalDiffTime =-  unnamedParser <?> "nominalDiffTime"-  where-    unnamedParser =-      do-        amount <- scientific-        factor <- timeUnitFactor-        return (factor (realToFrac amount))--timeUnitFactor :: Fractional a => Parser (a -> a)-timeUnitFactor =-  takeWhile isAlpha >>= \case-    "" -> return id-    "s" -> return id-    "ms" -> return (/ 1000)-    "μs" -> return (/ 1000000)-    "us" -> return (/ 1000000)-    "ns" -> return (/ 1000000000)-    "ps" -> return (/ 1000000000000)-    "m" -> return (* 60)-    "h" -> return (* 3600)-    "d" -> return (* 86400)-    unit -> fail ("Unsupported unit: " <> show unit)
+ library/Attoparsec/Time/ByteString.hs view
@@ -0,0 +1,318 @@+{-|+ASCII ByteString Parsers.+-}+module Attoparsec.Time.ByteString+(+  timeOfDayInISO8601,+  dayInISO8601,+  timeZoneInISO8601,+  utcTimeInISO8601,+  diffTime,+  nominalDiffTime,+)+where++import Attoparsec.Time.Prelude hiding (take, takeWhile)+import Data.Attoparsec.ByteString+import qualified Attoparsec.Time.Pure as A+import qualified Attoparsec.Time.Validation as B+import qualified Data.ByteString as C+import qualified Data.Attoparsec.ByteString.Char8 as D+++validated :: Show a => B.Validator a -> Parser a -> Parser a+validated validator parser =+  parser >>= \x -> B.run validator (pure x) fail x++sign :: Parser Bool+sign =+  anyWord8 >>= \case+    43 -> return True+    45 -> return False+    _ -> empty++decimalOfLength :: Integral a => Int -> Parser a+decimalOfLength length =+  do+    bytes <- take length+    if C.all A.word8IsAsciiDigit bytes+      then return (A.decimalFromBytes bytes)+      else fail "Not all chars are valid decimals"++picoWithBasisOfLength :: Int -> Parser Pico+picoWithBasisOfLength basisLength =+  MkFixed <$> ((+) <$> beforePoint <*> ((word8 46 *> afterPoint) <|> pure 0))+  where+    beforePoint =+      (* (10 ^ 12)) <$> decimalOfLength basisLength+    afterPoint =+      fmap (updater . C.take 12) (takeWhile1 A.word8IsAsciiDigit)+      where+        updater bytes =+          let +            afterPoint =+              A.decimalFromBytes bytes+            afterPointLength =+              C.length bytes+            paddedAfterPoint = +              if afterPointLength < 12+                then afterPoint * (10 ^ (12 - afterPointLength))+                else afterPoint+            in paddedAfterPoint++{-# INLINE hour #-}+hour :: Parser Int+hour =+  validated B.hour (decimalOfLength 2) <?> "hour"++{-# INLINE minute #-}+minute :: Parser Int+minute =+  validated B.minute (decimalOfLength 2) <?> "minute"++{-# INLINE second #-}+second :: Parser Pico+second =+  validated B.second (picoWithBasisOfLength 2) <?> "second"++{-|+>>> parseOnly timeOfDayInISO8601 "05:03:58"+Right 05:03:58++>>> parseOnly timeOfDayInISO8601 "05:03:58.02"+Right 05:03:58.02++>>> parseOnly timeOfDayInISO8601 "05:03:58.020"+Right 05:03:58.02++Checks the elements to be within a proper range:++>>> parseOnly timeOfDayInISO8601 "24:00:00"+Left "timeOfDayInISO8601 > hour: Failed reading: Validator \"hour\" failed on the following input: 24"++>>> parseOnly timeOfDayInISO8601 "00:00:60"+Left "timeOfDayInISO8601 > second: Failed reading: Validator \"second\" failed on the following input: 60.000000000000"++Checks the elements to be of proper length:++>>> parseOnly timeOfDayInISO8601 "1:00:00"+Left "timeOfDayInISO8601 > hour: Failed reading: Not all chars are valid decimals"++>>> parseOnly timeOfDayInISO8601 "01:1:00"+Left "timeOfDayInISO8601 > minute: Failed reading: Not all chars are valid decimals"+-}+{-# INLINE timeOfDayInISO8601 #-}+timeOfDayInISO8601 :: Parser TimeOfDay+timeOfDayInISO8601 =+  unnamedParser <?> "timeOfDayInISO8601"+  where+    unnamedParser =+      A.timeOfDay <$>+      (hour <* word8 58) <*>+      (minute <* word8 58) <*>+      (second)++{-|+>>> parseOnly dayInISO8601 "2017-02-01"+Right 2017-02-01++Checks the elements to be in proper range:++>>> parseOnly dayInISO8601 "2017-13-01"+Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,13,1)"++That is accounting for leap year:++>>> parseOnly dayInISO8601 "2017-02-29"+Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,2,29)"++>>> parseOnly dayInISO8601 "2016-02-29"+Right 2016-02-29+-}+{-# INLINE dayInISO8601 #-}+dayInISO8601 :: Parser Day+dayInISO8601 =+  unnamedParser <?> "dayInISO8601"+  where+    unnamedParser =+      do+        year <- decimalOfLength 4+        word8 45+        month <- decimalOfLength 2+        word8 45+        day <- decimalOfLength 2+        case fromGregorianValid year month day of+          Just day -> return day+          Nothing -> fail (error year month day)+      where+        error year month day =+          showString "Invalid combination of year month and day: " $ +          show (year, month, day)++{-|+>>> parseOnly timeZoneInISO8601 "+01:00"+Right +0100++>>> parseOnly timeZoneInISO8601 "+0100"+Right +0100++>>> parseOnly timeZoneInISO8601 "-0100"+Right -0100++>>> parseOnly timeZoneInISO8601 "Z"+Right UTC+-}+timeZoneInISO8601 :: Parser TimeZone+timeZoneInISO8601 =+  unnamedParser <?> "timeZoneInISO8601"+  where+    unnamedParser =+      z <|> offset+      where+        z =+          word8 90 $> utc+        offset =+          A.timeZone <$> sign <*> decimalOfLength 2 <*> (word8 58 *> decimalOfLength 2 <|> decimalOfLength 2 <|> pure 0)++{-|+>>> parseOnly utcTimeInISO8601 "2017-02-01T05:03:58+01:00"+Right 2017-02-01 04:03:58 UTC+-}+utcTimeInISO8601 :: Parser UTCTime+utcTimeInISO8601 =+  unnamedParser <?> "utcTimeInISO8601"+  where+    unnamedParser =+      do+        day <- dayInISO8601+        word8 84+        time <- timeOfDayInISO8601+        zone <- timeZoneInISO8601+        return (A.utcTimeFromDayAndTimeOfDay day time zone)++{-|+No suffix implies the "seconds" unit:++>>> parseOnly diffTime "10"+Right 10s++Various units (seconds, minutes, hours, days):++>>> parseOnly diffTime "10s"+Right 10s++>>> parseOnly diffTime "10m"+Right 600s++>>> parseOnly diffTime "10h"+Right 36000s++>>> parseOnly diffTime "10d"+Right 864000s++Metric prefixes to seconds (down to Pico):++>>> parseOnly diffTime "10ms"+Right 0.01s++Notice that \"μs\" is not supported, because it's not ASCII.++>>> parseOnly diffTime "10us"+Right 0.00001s++>>> parseOnly diffTime "10ns"+Right 0.00000001s++>>> parseOnly diffTime "10ps"+Right 0.00000000001s++Negative values:++>>> parseOnly diffTime "-1s"+Right -1s++Unsupported units:++>>> parseOnly diffTime "1k"+Left "diffTime: Failed reading: Unsupported unit: \"k\""+-}+diffTime :: Parser DiffTime+diffTime =+  unnamedParser <?> "diffTime"+  where+    unnamedParser =+      do+        amount <- D.scientific+        factor <- timeUnitFactor+        return (factor (realToFrac amount))++{-|+No suffix implies the "seconds" unit:++>>> parseOnly nominalDiffTime "10"+Right 10s++Various units (seconds, minutes, hours, days):++>>> parseOnly nominalDiffTime "10s"+Right 10s++>>> parseOnly nominalDiffTime "10m"+Right 600s++>>> parseOnly nominalDiffTime "10h"+Right 36000s++>>> parseOnly nominalDiffTime "10d"+Right 864000s++Metric prefixes to seconds (down to Pico):++>>> parseOnly nominalDiffTime "10ms"+Right 0.01s++Notice that \"μs\" is not supported, because it's not ASCII.++>>> parseOnly nominalDiffTime "10us"+Right 0.00001s++>>> parseOnly nominalDiffTime "10ns"+Right 0.00000001s++>>> parseOnly nominalDiffTime "10ps"+Right 0.00000000001s++Negative values:++>>> parseOnly nominalDiffTime "-1s"+Right -1s++Unsupported units:++>>> parseOnly nominalDiffTime "1k"+Left "nominalDiffTime: Failed reading: Unsupported unit: \"k\""+-}+nominalDiffTime :: Parser NominalDiffTime+nominalDiffTime =+  unnamedParser <?> "nominalDiffTime"+  where+    unnamedParser =+      do+        amount <- D.scientific+        factor <- timeUnitFactor+        return (factor (realToFrac amount))++timeUnitFactor :: Fractional a => Parser (a -> a)+timeUnitFactor =+  takeWhile A.word8IsAsciiAlpha >>= \case+    "" -> return id+    "s" -> return id+    "ms" -> return (/ 1000)+    "μs" -> return (/ 1000000)+    "us" -> return (/ 1000000)+    "ns" -> return (/ 1000000000)+    "ps" -> return (/ 1000000000000)+    "m" -> return (* 60)+    "h" -> return (* 3600)+    "d" -> return (* 86400)+    unit -> fail ("Unsupported unit: " <> show unit)
− library/Attoparsec/Time/Constructors.hs
@@ -1,38 +0,0 @@--- |--- Efficient construction functions for values of the \"time\" library.-module Attoparsec.Time.Constructors where--import Attoparsec.Time.Prelude---{-# INLINE timeZone #-}-timeZone :: Bool -> Int -> Int -> TimeZone-timeZone positive hour minute =-  minutesToTimeZone $-  bool negate id positive $-  hour * 60 + minute--{-# INLINE day #-}-day :: Int -> Int -> Int -> Day-day y m d =-  fromGregorian (fromIntegral y) m d--{-# INLINE timeOfDay #-}-timeOfDay :: Int -> Int -> Pico -> TimeOfDay-timeOfDay =-  TimeOfDay--{-# INLINE zonedTime #-}-zonedTime :: Day -> TimeOfDay -> TimeZone -> ZonedTime-zonedTime day tod tz =-  ZonedTime (LocalTime day tod) tz--{-# INLINE utcTimeFromDayAndTimeOfDay #-}-utcTimeFromDayAndTimeOfDay :: Day -> TimeOfDay -> TimeZone -> UTCTime-utcTimeFromDayAndTimeOfDay day tod tz =-  zonedTimeToUTC (zonedTime day tod tz)--{-# INLINE utcTimeFromComponents #-}-utcTimeFromComponents :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> TimeZone -> UTCTime-utcTimeFromComponents year month day hour minute second millisecond timeZone =-  undefined
+ library/Attoparsec/Time/Pure.hs view
@@ -0,0 +1,55 @@+module Attoparsec.Time.Pure where++import Attoparsec.Time.Prelude+import qualified Data.ByteString as A+++{-# INLINE timeZone #-}+timeZone :: Bool -> Int -> Int -> TimeZone+timeZone positive hour minute =+  minutesToTimeZone $+  bool negate id positive $+  hour * 60 + minute++{-# INLINE day #-}+day :: Int -> Int -> Int -> Day+day y m d =+  fromGregorian (fromIntegral y) m d++{-# INLINE timeOfDay #-}+timeOfDay :: Int -> Int -> Pico -> TimeOfDay+timeOfDay =+  TimeOfDay++{-# INLINE zonedTime #-}+zonedTime :: Day -> TimeOfDay -> TimeZone -> ZonedTime+zonedTime day tod tz =+  ZonedTime (LocalTime day tod) tz++{-# INLINE utcTimeFromDayAndTimeOfDay #-}+utcTimeFromDayAndTimeOfDay :: Day -> TimeOfDay -> TimeZone -> UTCTime+utcTimeFromDayAndTimeOfDay day tod tz =+  zonedTimeToUTC (zonedTime day tod tz)++{-# INLINE utcTimeFromComponents #-}+utcTimeFromComponents :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> TimeZone -> UTCTime+utcTimeFromComponents year month day hour minute second millisecond timeZone =+  undefined++{-# INLINE decimalFromBytes #-}+decimalFromBytes :: Integral decimal => A.ByteString -> decimal+decimalFromBytes =+  A.foldl' step 0+  where+    step a b =+      a * 10 + fromIntegral b - 48++{-# INLINE word8IsAsciiDigit #-}+word8IsAsciiDigit :: Word8 -> Bool+word8IsAsciiDigit w =+  w - 48 <= 9++{-# INLINE word8IsAsciiAlpha #-}+word8IsAsciiAlpha :: Word8 -> Bool+word8IsAsciiAlpha x =+  (x - 97 <= 25) || (x - 65 <= 25) 
+ library/Attoparsec/Time/Text.hs view
@@ -0,0 +1,332 @@+module Attoparsec.Time.Text+(+  timeOfDayInISO8601,+  dayInISO8601,+  timeZoneInISO8601,+  utcTimeInISO8601,+  diffTime,+  nominalDiffTime,+)+where++import Attoparsec.Time.Prelude hiding (take, takeWhile)+import Data.Attoparsec.Text+import qualified Attoparsec.Time.Pure as A+import qualified Attoparsec.Time.Validation as B+import qualified Data.Text as C+++validated :: Show a => B.Validator a -> Parser a -> Parser a+validated validator parser =+  parser >>= \x -> B.run validator (pure x) fail x++sign :: Parser Bool+sign =+  anyChar >>= \case+    '+' -> return True+    '-' -> return False+    _ -> empty++decimalChar :: Parser Int+decimalChar =+  satisfyWith ((subtract 48) . ord) ((&&) <$> (>= 0) <*> (<= 9))++decimalOfLength :: Num a => Int -> Parser a+decimalOfLength length =+  foldl' (\a b -> a * 10 + b) 0 <$>+  replicateM length (fmap fromIntegral decimalChar) <|>+  fail "Invalid decimal length"++shortMonth :: Parser Int+shortMonth =+  liftM C.toLower (take 3) >>= \case+    "jan" -> return 1+    "feb" -> return 2+    "mar" -> return 3+    "apr" -> return 4+    "may" -> return 5+    "jun" -> return 6+    "jul" -> return 7+    "aug" -> return 8+    "sep" -> return 9+    "oct" -> return 10+    "nov" -> return 11+    "dec" -> return 12+    _ -> empty++picoWithBasisOfLength :: Int -> Parser Pico+picoWithBasisOfLength basisLength =+  (\a b -> MkFixed (foldl' (\a b -> a * 10 + fromIntegral b) 0 (a ++ b))) <$> beforePoint <*> afterPoint+  where+    resolution =+      12+    beforePoint =+      replicateM basisLength decimalChar+    afterPoint =+      padListFromRight 0 [] resolution <$> ((char '.' *> many decimalChar) <|> pure [])+      where+        padListFromRight padding accumulator length list =+          case length of+            0 -> reverse accumulator+            _ -> case list of+              head : tail -> padListFromRight padding (head : accumulator) (pred length) tail+              _ -> reverse accumulator ++ replicate length padding++{-# INLINE hour #-}+hour :: Parser Int+hour =+  validated B.hour (decimalOfLength 2) <?> "hour"++{-# INLINE minute #-}+minute :: Parser Int+minute =+  validated B.minute (decimalOfLength 2) <?> "minute"++{-# INLINE second #-}+second :: Parser Pico+second =+  validated B.second (picoWithBasisOfLength 2) <?> "second"++{-|+>>> parseOnly timeOfDayInISO8601 "05:03:58"+Right 05:03:58++>>> parseOnly timeOfDayInISO8601 "05:03:58.02"+Right 05:03:58.02++>>> parseOnly timeOfDayInISO8601 "05:03:58.020"+Right 05:03:58.02++Checks the elements to be within a proper range:++>>> parseOnly timeOfDayInISO8601 "24:00:00"+Left "timeOfDayInISO8601 > hour: Failed reading: Validator \"hour\" failed on the following input: 24"++>>> parseOnly timeOfDayInISO8601 "00:00:60"+Left "timeOfDayInISO8601 > second: Failed reading: Validator \"second\" failed on the following input: 60.000000000000"++Checks the elements to be of proper length:++>>> parseOnly timeOfDayInISO8601 "1:00:00"+Left "timeOfDayInISO8601 > hour: Failed reading: Invalid decimal length"++>>> parseOnly timeOfDayInISO8601 "01:1:00"+Left "timeOfDayInISO8601 > minute: Failed reading: Invalid decimal length"+-}+{-# INLINE timeOfDayInISO8601 #-}+timeOfDayInISO8601 :: Parser TimeOfDay+timeOfDayInISO8601 =+  unnamedParser <?> "timeOfDayInISO8601"+  where+    unnamedParser =+      A.timeOfDay <$>+      (hour <* char ':') <*>+      (minute <* char ':') <*>+      (second)++{-|+>>> parseOnly dayInISO8601 "2017-02-01"+Right 2017-02-01++Checks the elements to be in proper range:++>>> parseOnly dayInISO8601 "2017-13-01"+Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,13,1)"++That is accounting for leap year:++>>> parseOnly dayInISO8601 "2017-02-29"+Left "dayInISO8601: Failed reading: Invalid combination of year month and day: (2017,2,29)"++>>> parseOnly dayInISO8601 "2016-02-29"+Right 2016-02-29+-}+{-# INLINE dayInISO8601 #-}+dayInISO8601 :: Parser Day+dayInISO8601 =+  unnamedParser <?> "dayInISO8601"+  where+    unnamedParser =+      do+        year <- decimalOfLength 4+        char '-'+        month <- decimalOfLength 2+        char '-'+        day <- decimalOfLength 2+        case fromGregorianValid year month day of+          Just day -> return day+          Nothing -> fail (error year month day)+      where+        error year month day =+          showString "Invalid combination of year month and day: " $ +          show (year, month, day)++{-|+>>> parseOnly timeZoneInISO8601 "+01:00"+Right +0100++>>> parseOnly timeZoneInISO8601 "+0100"+Right +0100++>>> parseOnly timeZoneInISO8601 "-0100"+Right -0100++>>> parseOnly timeZoneInISO8601 "Z"+Right UTC+-}+timeZoneInISO8601 :: Parser TimeZone+timeZoneInISO8601 =+  unnamedParser <?> "timeZoneInISO8601"+  where+    unnamedParser =+      z <|> offset+      where+        z =+          char 'Z' $> utc+        offset =+          A.timeZone <$> sign <*> decimalOfLength 2 <*> (char ':' *> decimalOfLength 2 <|> decimalOfLength 2 <|> pure 0)++{-|+>>> parseOnly utcTimeInISO8601 "2017-02-01T05:03:58+01:00"+Right 2017-02-01 04:03:58 UTC+-}+utcTimeInISO8601 :: Parser UTCTime+utcTimeInISO8601 =+  unnamedParser <?> "utcTimeInISO8601"+  where+    unnamedParser =+      do+        day <- dayInISO8601+        char 'T'+        time <- timeOfDayInISO8601+        zone <- timeZoneInISO8601+        return (A.utcTimeFromDayAndTimeOfDay day time zone)++{-|+No suffix implies the "seconds" unit:++>>> parseOnly diffTime "10"+Right 10s++Various units (seconds, minutes, hours, days):++>>> parseOnly diffTime "10s"+Right 10s++>>> parseOnly diffTime "10m"+Right 600s++>>> parseOnly diffTime "10h"+Right 36000s++>>> parseOnly diffTime "10d"+Right 864000s++Metric prefixes to seconds (down to Pico):++>>> parseOnly diffTime "10ms"+Right 0.01s++>>> parseOnly diffTime "10μs"+Right 0.00001s++>>> parseOnly diffTime "10us"+Right 0.00001s++>>> parseOnly diffTime "10ns"+Right 0.00000001s++>>> parseOnly diffTime "10ps"+Right 0.00000000001s++Negative values:++>>> parseOnly diffTime "-1s"+Right -1s++Unsupported units:++>>> parseOnly diffTime "1k"+Left "diffTime: Failed reading: Unsupported unit: \"k\""+-}+diffTime :: Parser DiffTime+diffTime =+  unnamedParser <?> "diffTime"+  where+    unnamedParser =+      do+        amount <- scientific+        factor <- timeUnitFactor+        return (factor (realToFrac amount))++{-|+No suffix implies the "seconds" unit:++>>> parseOnly nominalDiffTime "10"+Right 10s++Various units (seconds, minutes, hours, days):++>>> parseOnly nominalDiffTime "10s"+Right 10s++>>> parseOnly nominalDiffTime "10m"+Right 600s++>>> parseOnly nominalDiffTime "10h"+Right 36000s++>>> parseOnly nominalDiffTime "10d"+Right 864000s++Metric prefixes to seconds (down to Pico):++>>> parseOnly nominalDiffTime "10ms"+Right 0.01s++>>> parseOnly nominalDiffTime "10μs"+Right 0.00001s++>>> parseOnly nominalDiffTime "10us"+Right 0.00001s++>>> parseOnly nominalDiffTime "10ns"+Right 0.00000001s++>>> parseOnly nominalDiffTime "10ps"+Right 0.00000000001s++Negative values:++>>> parseOnly nominalDiffTime "-1s"+Right -1s++Unsupported units:++>>> parseOnly nominalDiffTime "1k"+Left "nominalDiffTime: Failed reading: Unsupported unit: \"k\""+-}+nominalDiffTime :: Parser NominalDiffTime+nominalDiffTime =+  unnamedParser <?> "nominalDiffTime"+  where+    unnamedParser =+      do+        amount <- scientific+        factor <- timeUnitFactor+        return (factor (realToFrac amount))++timeUnitFactor :: Fractional a => Parser (a -> a)+timeUnitFactor =+  takeWhile isAlpha >>= \case+    "" -> return id+    "s" -> return id+    "ms" -> return (/ 1000)+    "μs" -> return (/ 1000000)+    "us" -> return (/ 1000000)+    "ns" -> return (/ 1000000000)+    "ps" -> return (/ 1000000000000)+    "m" -> return (* 60)+    "h" -> return (* 3600)+    "d" -> return (* 86400)+    unit -> fail ("Unsupported unit: " <> show unit)
+ library/Attoparsec/Time/Validation.hs view
@@ -0,0 +1,43 @@+module Attoparsec.Time.Validation where++import Attoparsec.Time.Prelude+++data Validator a =+  Validator String (a -> Bool)++run :: Show a => Validator a -> b -> (String -> b) -> a -> b+run (Validator name predicate) onNoError onError input =+  if predicate input+    then+      onNoError+    else+      onError $+      showString "Validator " $+      shows name $+      showString " failed on the following input: " $+      show input++month :: (Num a, Ord a) => Validator a+month =+  Validator "month" (liftA2 (&&) (>= 1) (<= 12))++monthDay :: (Num a, Ord a) => Validator a+monthDay =+  Validator "monthDay" (liftA2 (&&) (>= 1) (<= 31))++weekDay :: (Num a, Ord a) => Validator a+weekDay =+  Validator "weekDay" (liftA2 (&&) (>= 1) (<= 7))++hour :: (Num a, Ord a) => Validator a+hour =+  Validator "hour" (liftA2 (&&) (>= 0) (< 24))++minute :: (Num a, Ord a) => Validator a+minute =+  Validator "minute" (liftA2 (&&) (>= 0) (< 60))++second :: (Num a, Ord a) => Validator a+second =+  Validator "second" (liftA2 (&&) (>= 0) (< 60))
− library/Attoparsec/Time/Validators.hs
@@ -1,43 +0,0 @@-module Attoparsec.Time.Validators where--import Attoparsec.Time.Prelude---data Validator a =-  Validator String (a -> Bool)--run :: Show a => Validator a -> b -> (String -> b) -> a -> b-run (Validator name predicate) onNoError onError input =-  if predicate input-    then-      onNoError-    else-      onError $-      showString "Validator " $-      shows name $-      showString " failed on the following input: " $-      show input--month :: (Num a, Ord a) => Validator a-month =-  Validator "month" (liftA2 (&&) (>= 1) (<= 12))--monthDay :: (Num a, Ord a) => Validator a-monthDay =-  Validator "monthDay" (liftA2 (&&) (>= 1) (<= 31))--weekDay :: (Num a, Ord a) => Validator a-weekDay =-  Validator "weekDay" (liftA2 (&&) (>= 1) (<= 7))--hour :: (Num a, Ord a) => Validator a-hour =-  Validator "hour" (liftA2 (&&) (>= 0) (< 24))--minute :: (Num a, Ord a) => Validator a-minute =-  Validator "minute" (liftA2 (&&) (>= 0) (< 60))--second :: (Num a, Ord a) => Validator a-second =-  Validator "second" (liftA2 (&&) (>= 0) (< 60))