X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Data%2FTime%2FRFC822%2FParsec.hs;fp=Data%2FTime%2FRFC822%2FParsec.hs;h=f80633efb5fbd60987f14fc097252d0671fb1795;hb=9f9ed0471883b50fec1b091621f332d62477a34c;hp=0000000000000000000000000000000000000000;hpb=746e89579242035ff05ceec12dd151b4b9931a5f;p=time-http.git diff --git a/Data/Time/RFC822/Parsec.hs b/Data/Time/RFC822/Parsec.hs new file mode 100644 index 0000000..f80633e --- /dev/null +++ b/Data/Time/RFC822/Parsec.hs @@ -0,0 +1,133 @@ +{-# LANGUAGE FlexibleContexts #-} +module Data.Time.RFC822.Parsec + ( parser + ) + where + +import Control.Monad +import Data.Fixed +import Data.Time +import Data.Time.Calendar.WeekDate +import Data.Time.HTTP.Common +import Text.Parsec + + +parser :: Stream s m Char => ParsecT s u m ZonedTime +parser = dateTime + + +dateTime :: Stream s m Char => ParsecT s u m ZonedTime +dateTime = do weekDay <- optionMaybe $ + do w <- shortWeekDayNameP + _ <- string ", " + return w + gregDay <- date + case weekDay of + Nothing + -> return () -- No day in week exists. + Just givenWD + -> let (_, _, correctWD) = toWeekDate gregDay + in + if correctWD == givenWD then + return () -- Correct day in the week. + else + let (year, month, day) = toGregorian gregDay + in + fail $ concat [ "Gregorian day " + , show year + , "-" + , show month + , "-" + , show day + , " is " + , longWeekDayName correctWD + , ", not " + , longWeekDayName givenWD + ] + (tod, timeZone) <- time + return ZonedTime { + zonedTimeToLocalTime = LocalTime { + localDay = gregDay + , localTimeOfDay = tod + } + , zonedTimeZone = timeZone + } + +date :: Stream s m Char => ParsecT s u m Day +date = do day <- read2 + _ <- char ' ' + month <- shortMonthNameP + _ <- char ' ' + year <- liftM (+ 1900) read2 + _ <- char ' ' + + case fromGregorianValid (toInteger year) month day of + Nothing + -> fail $ concat [ "Invalid gregorian day: " + , show year + , "-" + , show month + , "-" + , show day + ] + Just gregDay + -> return gregDay + +time :: Stream s m Char => ParsecT s u m (TimeOfDay, TimeZone) +time = do tod <- hour + _ <- char ' ' + tz <- zone + return (tod, tz) + +hour :: Stream s m Char => ParsecT s u m TimeOfDay +hour = do hour <- read2 + minute <- char ':' >> read2 + second <- option 0 (char ':' >> read2) + case makeTimeOfDayValid hour minute second of + Nothing + -> fail $ concat [ "Invalid time of day: " + , show hour + , ":" + , show minute + , ":" + , showFixed True second + ] + Just tod + -> return tod + +zone :: Stream s m Char => ParsecT s u m TimeZone +zone = choice [ string "UT" >> return (TimeZone 0 False "UT" ) + , string "GMT" >> return (TimeZone 0 False "GMT") + , char 'E' + >> choice [ string "ST" >> return (TimeZone ((-5) * 60) False "EST") + , string "DT" >> return (TimeZone ((-4) * 60) True "EDT") + ] + , char 'C' + >> choice [ string "ST" >> return (TimeZone ((-6) * 60) False "CST") + , string "DT" >> return (TimeZone ((-5) * 60) True "CDT") + ] + , char 'M' + >> choice [ string "ST" >> return (TimeZone ((-7) * 60) False "MST") + , string "DT" >> return (TimeZone ((-6) * 60) True "MDT") + , return (TimeZone ((-12) * 60) False "M") + ] + , char 'P' + >> choice [ string "ST" >> return (TimeZone ((-8) * 60) False "PST") + , string "DT" >> return (TimeZone ((-7) * 60) True "PDT") + ] + , char 'Z' >> return (TimeZone 0 False "Z") + , char 'A' >> return (TimeZone ((-1) * 60) False "A") + , char 'N' >> return (TimeZone ( 1 * 60) False "N") + , char 'Y' >> return (TimeZone ( 12 * 60) False "Y") + , do sign <- (char '+' >> return 1) + <|> + (char '-' >> return (-1)) + hour <- read2 + minute <- read2 + let tz = TimeZone { + timeZoneMinutes = (sign * (hour * 60 + minute)) + , timeZoneSummerOnly = False + , timeZoneName = timeZoneOffsetString tz + } + return tz + ]