[darcs-users] date/time parser (was: File name too long)
Peter Simons
simons at cryp.to
Tue Oct 14 18:26:50 UTC 2003
I wrote:
> I have code that parses date specs into 'CalendarTime' in
> my parser for RFC 2822. It should be trivial to modify
> that to read darcs' format.
It was. Here we go:
\begin{code}
import Text.ParserCombinators.Parsec
import System.Time
import Data.Char ( toUpper, ord )
import Control.Monad ( liftM2 )
main :: IO ()
main = print $ parse date_time "" input
where
input = "Sun_May_11_06.13.27_EDT_2003"
----- Parser Combinators ---------------------------------------------
-- |Case-insensitive variant of Parsec's 'char' function.
caseChar :: Char -> GenParser Char a Char
caseChar c = satisfy (\x -> toUpper x == toUpper c)
-- |Case-insensitive variant of Parsec's 'string' function.
caseString :: String -> GenParser Char a ()
caseString cs = mapM_ caseChar cs <?> cs
-- |Match a parser at least @n@ times.
manyN :: Int -> GenParser a b c -> GenParser a b [c]
manyN n p
| n <= 0 = return []
| otherwise = liftM2 (++) (count n p) (many p)
-- |Match a parser at least @n@ times, but no more than @m@ times.
manyNtoM :: Int -> Int -> GenParser a b c -> GenParser a b [c]
manyNtoM n m p
| n < 0 = return []
| n > m = return []
| n == m = count n p
| n == 0 = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m]))
| otherwise = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p)
----- Date/Time Parser -----------------------------------------------
date_time :: CharParser a CalendarTime
date_time = do wd <- day_name
char '_'
mon <- month_name
char '_'
d <- day
char '_'
h <- hour
char '.'
m <- minute
char '.'
s <- second
char '_'
z <- zone
char '_'
y <- year
return (CalendarTime y mon d h m s 0 wd 0 "" z False)
day_name :: CharParser a Day
day_name = choice
[ caseString "Mon" >> return Monday
, try (caseString "Tue") >> return Tuesday
, caseString "Wed" >> return Wednesday
, caseString "Thu" >> return Thursday
, caseString "Fri" >> return Friday
, try (caseString "Sat") >> return Saturday
, caseString "Sun" >> return Sunday
]
year :: CharParser a Int
year = do y <- manyN 4 digit
return (read y :: Int)
month_name :: CharParser a Month
month_name = choice
[ try (caseString "Jan") >> return January
, caseString "Feb" >> return February
, try (caseString "Mar") >> return March
, try (caseString "Apr") >> return April
, caseString "May" >> return May
, try (caseString "Jun") >> return June
, caseString "Jul" >> return July
, caseString "Aug" >> return August
, caseString "Sep" >> return September
, caseString "Oct" >> return October
, caseString "Nov" >> return November
, caseString "Dec" >> return December
]
day :: CharParser a Int
day = do d <- manyNtoM 1 2 digit
return (read d :: Int)
hour :: CharParser a Int
hour = do r <- count 2 digit
return (read r :: Int)
minute :: CharParser a Int
minute = do r <- count 2 digit
return (read r :: Int)
second :: CharParser a Int
second = do r <- count 2 digit
return (read r :: Int)
zone :: CharParser a Int
zone = choice
[ do { char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) }
, do { char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) }
, mkZone "UT" 0
, mkZone "GMT" 0
, mkZone "EST" (-5)
, mkZone "EDT" (-4)
, mkZone "CST" (-6)
, mkZone "CDT" (-5)
, mkZone "MST" (-7)
, mkZone "MDT" (-6)
, mkZone "PST" (-8)
, mkZone "PDT" (-7)
, do { r <- oneOf ['A'..'I']; return $ (ord r - 64) * 60*60 }
, do { r <- oneOf ['K'..'M']; return $ (ord r - 65) * 60*60 }
, do { r <- oneOf ['N'..'Y']; return $ -(ord r - 77) * 60*60 }
, do { char 'Z'; return 0 }
]
where mkZone n o = try $ do { caseString n; return (o*60*60) }
\end{code}
More information about the darcs-users
mailing list