dates 0.1.2.0 → 0.2.0.0
raw patch · 5 files changed
+245/−85 lines, 5 files
Files
- Data/Dates.hs +2/−83
- Data/Dates/Formats.hs +110/−0
- Data/Dates/Internal.hs +50/−0
- Data/Dates/Types.hs +75/−0
- dates.cabal +8/−2
Data/Dates.hs view
@@ -18,60 +18,8 @@ import Text.Parsec.String import Data.Generics --- | Date / Time-data DateTime =- DateTime {- year ∷ Int,- month ∷ Int,- day ∷ Int,- hour ∷ Int,- minute ∷ Int,- second ∷ Int }- deriving (Eq,Ord,Data,Typeable)---- | 12 months names.-months ∷ [String]-months = ["january",- "february",- "march",- "april",- "may",- "june",- "july",- "august",- "september",- "october",- "november",- "december"]---- | capitalize first letter of the string-capitalize ∷ String → String-capitalize [] = []-capitalize (x:xs) = (toUpper x):xs---- | Show name of given month-showMonth ∷ Int → String-showMonth i = capitalize $ months !! (i-1)--instance Show DateTime where- show (DateTime y m d h mins s) = - show d ⧺ " " ⧺ showMonth m ⧺ " " ⧺ show y ⧺ ", " ⧺- show h ⧺ ":" ⧺ show mins ⧺ ":" ⧺ show s---- | Only time, without date-data Time = - Time {- tHour ∷ Int,- tMinute ∷ Int,- tSecond ∷ Int }- deriving (Eq,Ord,Show,Data,Typeable)---- | Parser version of Prelude.read-tryRead :: Read a => String -> Parsec String st a-tryRead str =- case reads str of- [(res, "")] -> return res- _ -> fail $ "Cannot read: " ++ str+import Data.Dates.Types+import Data.Dates.Internal -- | Get current date and time. getCurrentDateTime ∷ IO DateTime@@ -111,35 +59,6 @@ hour = tHour t + hour dt, minute = tMinute t + minute dt, second = tSecond t + second dt }--times ∷ Int → Parsec String st t → Parsec String st [t]-times 0 _ = return []-times n p = do- ts ← times (n-1) p- t ← optionMaybe p- case t of- Just t' → return (ts ++ [t'])- Nothing → return ts- -number ∷ Int → Int → Parsec String st Int-number n m = do- t ← tryRead =<< (n `times` digit)- if t > m- then fail "number too large"- else return t--pYear ∷ Parsec String st Int-pYear = do- y ← number 4 10000- if y < 2000- then return (y+2000)- else return y--pMonth ∷ Parsec String st Int-pMonth = number 2 12--pDay ∷ Parsec String st Int-pDay = number 2 31 euroNumDate ∷ Parsec String st DateTime euroNumDate = do
+ Data/Dates/Formats.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE UnicodeSyntax, DeriveDataTypeable #-}+-- | This module allows to parse arbitrary date formats.+-- Date formats are specified as strings:+--+-- * "DD.MM.YYY"+--+-- * "YYYY\/MM\/DD"+--+-- * "DD\/MM\/YYYY, HH:mm:SS"+--+-- * and so on.+--+module Data.Dates.Formats+ (FormatElement (..), Format,+ pFormat, formatParser,+ parseDateFormat+ ) where++import Control.Applicative ((<$>))+import Data.Monoid+import Text.Parsec++import Data.Dates.Types+import Data.Dates.Internal (number)++-- | Date\/time format element+data FormatElement =+ YEAR Int+ | MONTH Int+ | DAY Int+ | HOUR Int+ | MINUTE Int+ | SECOND Int+ | Fixed String+ deriving (Eq, Show)++-- | Date\/time format+type Format = [FormatElement]++nchars ∷ Char → Parsec String st Int+nchars c = do+ s ← many1 $ char c+ return $ length s++-- | Parser for date\/time format.+pFormat ∷ Parsec String st Format+pFormat = many1 $ choice $ map try [pYear, pMonth, pDay,+ pHour, pMinute, pSecond,+ pFixed]+ where+ pYear = YEAR <$> nchars 'Y'+ pMonth = MONTH <$> nchars 'M'+ pDay = DAY <$> nchars 'D'+ pHour = HOUR <$> nchars 'H'+ pMinute = MINUTE <$> nchars 'm'+ pSecond = SECOND <$> nchars 'S'+ pFixed = Fixed <$> (many1 $ noneOf "YMDHmS")++pYear ∷ Int → Parsec String st DateTime+pYear n = do+ y ← number n 10000+ if y < 2000+ then return $ mempty {year = y+2000}+ else return $ mempty {year = y}++pMonth ∷ Int → Parsec String st DateTime+pMonth n = do+ m ← number n 12+ return $ mempty {month = m}++pDay ∷ Int → Parsec String st DateTime+pDay n = do+ d ← number n 31+ return $ mempty {day = d}++pHour ∷ Int → Parsec String st DateTime+pHour n = do+ h ← number n 23+ return $ mempty {hour = h}++pMinute ∷ Int → Parsec String st DateTime+pMinute n = do+ m ← number n 59+ return $ mempty {minute = m}++pSecond ∷ Int → Parsec String st DateTime+pSecond n = do+ s ← number n 59+ return $ mempty {second = s}++-- | Make Parser for specified date format.+formatParser ∷ Format → Parsec String st DateTime+formatParser format = mconcat <$> mapM parser format+ where+ parser (YEAR n) = pYear n+ parser (MONTH n) = pMonth n+ parser (DAY n) = pDay n+ parser (HOUR n) = pHour n+ parser (MINUTE n) = pMinute n+ parser (SECOND n) = pSecond n+ parser (Fixed s) = string s >> return mempty++-- | Parse date\/time in specified format.+parseDateFormat :: String -- ^ Format string, i.e. "DD.MM.YY"+ -> String -- ^ String to parse+ -> Either ParseError DateTime+parseDateFormat formatStr str = do+ format <- runParser pFormat () "(date format string)" formatStr+ runParser (formatParser format) () "(date)" str+
+ Data/Dates/Internal.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE UnicodeSyntax, DeriveDataTypeable #-}++module Data.Dates.Internal where++import Text.Parsec+import Text.Parsec.String++-- | Parser version of Prelude.read+tryRead :: Read a => String -> Parsec String st a+tryRead str =+ case reads str of+ [(res, "")] -> return res+ _ -> fail $ "Cannot read: " ++ str++-- | Apply parser N times+times ∷ Int+ → Parsec String st t+ → Parsec String st [t]+times 0 _ = return []+times n p = do+ ts ← times (n-1) p+ t ← optionMaybe p+ case t of+ Just t' → return (ts ++ [t'])+ Nothing → return ts+ +-- | Parse natural number of N digits+-- which is not greater than M+number ∷ Int -- ^ Number of digits+ → Int -- ^ Maximum value+ → Parsec String st Int+number n m = do+ t ← tryRead =<< (n `times` digit)+ if t > m+ then fail "number too large"+ else return t++pYear ∷ Parsec String st Int+pYear = do+ y ← number 4 10000+ if y < 2000+ then return (y+2000)+ else return y++pMonth ∷ Parsec String st Int+pMonth = number 2 12++pDay ∷ Parsec String st Int+pDay = number 2 31+
+ Data/Dates/Types.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE UnicodeSyntax, DeriveDataTypeable #-}++module Data.Dates.Types+ (DateTime (..),+ Time (..),+ months, capitalize+ ) where++import Prelude.Unicode+import Data.Monoid+import Data.Char+import Data.Generics++-- | Date / Time+data DateTime =+ DateTime {+ year ∷ Int,+ month ∷ Int,+ day ∷ Int,+ hour ∷ Int,+ minute ∷ Int,+ second ∷ Int }+ deriving (Eq,Ord,Data,Typeable)++-- | 12 months names.+months ∷ [String]+months = ["january",+ "february",+ "march",+ "april",+ "may",+ "june",+ "july",+ "august",+ "september",+ "october",+ "november",+ "december"]++-- | capitalize first letter of the string+capitalize ∷ String → String+capitalize [] = []+capitalize (x:xs) = (toUpper x):xs++-- | Show name of given month+showMonth ∷ Int → String+showMonth i = capitalize $ months !! (i-1)++instance Show DateTime where+ show (DateTime y m d h mins s) = + show d ⧺ " " ⧺ showMonth m ⧺ " " ⧺ show y ⧺ ", " ⧺+ show h ⧺ ":" ⧺ show mins ⧺ ":" ⧺ show s++-- | Only time, without date+data Time = + Time {+ tHour ∷ Int,+ tMinute ∷ Int,+ tSecond ∷ Int }+ deriving (Eq,Ord,Show,Data,Typeable)++instance Monoid DateTime where+ mempty = DateTime 0 0 0 0 0 0+ mappend dt1 dt2 =+ DateTime (year dt1 `plus` year dt2)+ (month dt1 `plus` month dt2)+ (day dt1 `plus` day dt2)+ (hour dt1 `plus` hour dt2)+ (minute dt1 `plus` minute dt2)+ (second dt1 `plus` second dt2)+ where+ plus :: Int → Int → Int+ plus 0 x = x+ plus x _ = x+
dates.cabal view
@@ -1,5 +1,5 @@ name: dates-version: 0.1.2.0+version: 0.2.0.0 synopsis: Small library for parsing different dates formats. description: This package allows to parse many different formats of dates. Both absolute and relative dates are supported.@@ -17,6 +17,9 @@ . 4-digits years may be abbreviated (such as 12 for 2012). Both 12-hour and 24-hour time formats are supported.+ .+ User-specified date formats are supported by+ Data.Dates.Formats module. homepage: http://redmine.iportnov.ru/projects/dates/ license: BSD3@@ -29,7 +32,10 @@ cabal-version: >=1.8 library- exposed-modules: Data.Dates+ exposed-modules: Data.Dates,+ Data.Dates.Types,+ Data.Dates.Formats,+ Data.Dates.Internal -- other-modules: build-depends: base ==4.5.*, base-unicode-symbols ==0.2.*,