text-time (empty) → 0.1.0
raw patch · 10 files changed
+297/−0 lines, 10 filesdep +Cabaldep +QuickCheckdep +attoparsecsetup-changed
Dependencies added: Cabal, QuickCheck, attoparsec, base, hspec, text, time
Files
- CHANGES.md +3/−0
- LICENSE +27/−0
- README.md +34/−0
- Setup.hs +2/−0
- benchmark/Benchmarks.hs +22/−0
- src/Data/Text/Time.hs +11/−0
- src/Data/Text/Time/Parsers.hs +107/−0
- test-src/Data/Text/TimeSpec.hs +29/−0
- test-src/Spec.hs +7/−0
- text-time.cabal +55/−0
+ CHANGES.md view
@@ -0,0 +1,3 @@+# Version 0.1 (2016-12-???)++ *
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2014 Krzysztof Langner+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * 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.++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.+
+ README.md view
@@ -0,0 +1,34 @@+[](https://travis-ci.org/klangner/text-time)+[](https://hackage.haskell.org/package/text-time)++# Welcome to Text Time library++This library contains fast parser for ISO date from Text into UTCTime data++++## Installation++```sh+stack setup+stack build+stack test+```+++# Join in!++We are happy to receive bug reports, fixes, documentation enhancements,+and other improvements.++Please report bugs via the+[github issue tracker](http://github.com/klangner/text-time/issues).++Master [git repository](http://github.com/klangner/text-time):++* `git clone https://github.com/klangner/text-time.git`+++# Redistributing++bytestring-time source code is distributed under the BSD3 License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchmark/Benchmarks.hs view
@@ -0,0 +1,22 @@++import Criterion.Main+import Data.Text+import Data.Time+import Data.ByteString.Time+++parseString :: String -> UTCTime+parseString str = parseTimeOrError True defaultTimeLocale "%Y-%m-%dT%H:%M:%S" str+++parseByteString :: Text -> UTCTime+parseByteString str = parseTimeOrError True defaultTimeLocale "%Y-%m-%dT%H:%M:%S" (unpack str)+++main :: IO ()+main = defaultMain+ [ bgroup "Time parsers"+ [ bench "String" $ nf parseString "2016-12-12T20:56:34"+ , bench "ByteString" $ nf parseISODateTime (pack "2016-12-12T20:56:34")+ ]+ ]
+ src/Data/Text/Time.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Parser for ISO date from ByteString+module Data.Text.Time+ ( module Data.Text.Time.Parsers+ ) where+++import Data.Text.Time.Parsers++
+ src/Data/Text/Time/Parsers.hs view
@@ -0,0 +1,107 @@++module Data.Text.Time.Parsers+ ( parseISODateTime+ , parseUTCTimeOrError+ ) where++-- import Prelude+import Control.Applicative+import Control.Monad (when)+import qualified Data.Attoparsec.Text as A+import Data.Bits ((.&.))+import Data.Char (isDigit, ord)+import qualified Data.Text as T+import Data.Time ( Day+ , TimeOfDay+ , UTCTime(..)+ , fromGregorian+ , fromGregorianValid+ , makeTimeOfDayValid+ , midnight+ , timeOfDayToTime+ )+++-- | Parse ISO date. If date can't be parsed then this function will return default value instead of error+-- Adapted from sqlite-simple package+parseISODateTime :: T.Text -> UTCTime+parseISODateTime str =+ case parseUTCTimeOrError str of+ Left _ -> defaultUTCTime+ Right dt -> dt+++-- | Default time if date can't be parsed+defaultUTCTime :: UTCTime+defaultUTCTime = UTCTime (fromGregorian 1 1 1) 0+++parseUTCTimeOrError :: T.Text -> Either String UTCTime+parseUTCTimeOrError = A.parseOnly getUTCTime++-- | Create UTCTime parser for ISO date time+-- This code is based on code from sqlite-simple package+--+getUTCTime :: A.Parser UTCTime+getUTCTime = do+ day <- getDay+ time <- ((A.char ' ' <|> A.char 'T') *> getTimeOfDay) <|> pure midnight+ let time' = timeOfDayToTime time+ return (UTCTime day time')+++-- | Date parser+getDay :: A.Parser Day+getDay = do+ yearStr <- A.takeWhile isDigit+ when (T.length yearStr < 4) (fail "year must consist of at least 4 digits")++ let year = toNum yearStr+ month <- (A.char '-' *> digits "month") <|> pure 1+ day <- (A.char '-' *> digits "day") <|> pure 1+ case fromGregorianValid year month day of+ Nothing -> fail "invalid date"+ Just x -> return $! x+++getTimeOfDay :: A.Parser TimeOfDay+getTimeOfDay = do+ hour <- digits "hours"+ _ <- A.char ':'+ minute <- digits "minutes"+ -- Allow omission of seconds. If seconds is omitted, don't try to+ -- parse the sub-second part.+ (sec,subsec)+ <- ((,) <$> (A.char ':' *> digits "seconds") <*> fract) <|> pure (0,0)++ let picos' = sec + subsec++ case makeTimeOfDayValid hour minute picos' of+ Nothing -> fail "invalid time of day"+ Just x -> return $! x++ where+ fract =+ (A.char '.' *> (decimal <$> A.takeWhile1 isDigit)) <|> pure 0+++toNum :: Num n => T.Text -> n+toNum = T.foldl' (\a c -> 10*a + digit c) 0+{-# INLINE toNum #-}++digit :: Num n => Char -> n+digit c = fromIntegral (ord c .&. 0x0f)+{-# INLINE digit #-}++digits :: Num n => String -> A.Parser n+digits msg = do+ x <- A.anyChar+ y <- A.anyChar+ if isDigit x && isDigit y+ then return $! (10 * digit x + digit y)+ else fail (msg ++ " is not 2 digits")+{-# INLINE digits #-}++decimal :: Fractional a => T.Text -> a+decimal str = toNum str / 10^(T.length str)+{-# INLINE decimal #-}
+ test-src/Data/Text/TimeSpec.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE OverloadedStrings #-}+module Data.Text.TimeSpec (spec) where++import Data.Text.Time+import Test.Hspec+import Data.Time+++spec :: Spec+spec = do++ describe "Parsers" $ do++ it "iso format: YYYY" $ do+ parseISODateTime "2014" `shouldBe` UTCTime (fromGregorian 2014 1 1) 0++ it "iso format: YYYY-MM" $ do+ parseISODateTime "2014-04" `shouldBe` UTCTime (fromGregorian 2014 4 1) 0++ it "iso format: YYYY-MM-DD" $ do+ parseISODateTime "2014-04-23" `shouldBe` UTCTime (fromGregorian 2014 4 23) 0++ it "iso format: YYYY-MM-DDTHH:MM:SS" $ do+ let t = timeOfDayToTime (TimeOfDay 12 34 56)+ parseISODateTime "2014-04-23T12:34:56" `shouldBe` UTCTime (fromGregorian 2014 4 23) t++ it "iso format: YYYY-MM-DD HH:MM:SS" $ do+ let t = timeOfDayToTime (TimeOfDay 12 34 56)+ parseISODateTime "2014-04-23 12:34:56" `shouldBe` UTCTime (fromGregorian 2014 4 23) t
+ test-src/Spec.hs view
@@ -0,0 +1,7 @@+import Test.Hspec+import qualified Data.Text.TimeSpec+++main :: IO ()+main = hspec $ do+ describe "Time" Data.Text.TimeSpec.spec
+ text-time.cabal view
@@ -0,0 +1,55 @@+name: text-time+version: 0.1.0+synopsis: Library for Time parsing from Text into UTCTime+License: BSD3+License-file: LICENSE+Extra-Source-Files:+ README.md,+ CHANGES.md,+ LICENSE,+ benchmark/*.hs+description:+ Fast parser for ISO date from Text to UTCTime+homepage: https://github.com/klangner/text-time+author: Krzysztof Langner+maintainer: klangner@gmail.com+category: Data+build-type: Simple+cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/klangner/text-time++library+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base >= 4.7 && < 5,+ attoparsec < 0.14,+ text < 2,+ time < 2+ exposed-modules:+ Data.Text.Time+ other-modules:+ Data.Text.Time.Parsers++test-suite unit-tests+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ default-language: Haskell2010+ build-depends:+ base >= 4 && <5,+ hspec >=2 && <3,+ QuickCheck >=2.6 && <3,+ Cabal >=1.16.0 && <2,+ attoparsec < 0.14,+ text < 2,+ time < 2+ other-modules:+ Data.Text.Time,+ Data.Text.TimeSpec+ hs-source-dirs:+ src,+ test-src