X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=time-http.git;a=blobdiff_plain;f=Data%2FTime%2FRFC1123.hs;h=cab3fb1f281e0584dbff583b6c12f27131cb728e;hp=93aeb7e2d924d0a5ee85112c376835a6baac7b0b;hb=0b73811;hpb=82afb594c5b4254385435491700befcbea185a5d diff --git a/Data/Time/RFC1123.hs b/Data/Time/RFC1123.hs index 93aeb7e..cab3fb1 100644 --- a/Data/Time/RFC1123.hs +++ b/Data/Time/RFC1123.hs @@ -1,3 +1,10 @@ +{-# LANGUAGE + FlexibleInstances + , MultiParamTypeClasses + , OverloadedStrings + , TemplateHaskell + , UnicodeSyntax + #-} -- |This module provides functions to parse and format RFC 1123 date -- and time formats. -- @@ -10,49 +17,91 @@ -- -- > year ::= 4DIGIT module Data.Time.RFC1123 - ( format - , parse + ( RFC1123 + , rfc1123DateAndTime ) where +import Control.Applicative +import Data.Ascii (Ascii, AsciiBuilder) +import qualified Data.Ascii as A +import Data.Attoparsec.Char8 +import Data.Convertible.Base +import Data.Monoid.Unicode +import Data.Tagged import Data.Time import Data.Time.Calendar.WeekDate import Data.Time.HTTP.Common -import Data.Time.RFC822 (showRFC822TimeZone) -import Data.Time.RFC1123.Internal +import Data.Time.RFC822.Internal +import Prelude.Unicode --- |Format a 'ZonedTime' in RFC 1123. -format :: ZonedTime -> String -format zonedTime +-- FIXME: doc +data RFC1123 + +instance ConvertSuccess ZonedTime (Tagged RFC1123 Ascii) where + {-# INLINE convertSuccess #-} + convertSuccess = (A.fromAsciiBuilder <$>) ∘ cs + +instance ConvertSuccess ZonedTime (Tagged RFC1123 AsciiBuilder) where + {-# INLINE convertSuccess #-} + convertSuccess = Tagged ∘ toAsciiBuilder + +instance ConvertAttempt (Tagged RFC1123 Ascii) ZonedTime where + {-# INLINE convertAttempt #-} + convertAttempt = parseAttempt' rfc1123DateAndTime ∘ untag + +-- |Parse an RFC 1123 date and time string. +rfc1123DateAndTime ∷ Parser ZonedTime +rfc1123DateAndTime = dateTime + +dateTime ∷ Parser ZonedTime +dateTime = do weekDay ← optionMaybe $ + do w ← shortWeekDayNameP + _ ← string ", " + return w + gregDay ← date + case weekDay of + Nothing + → return () + Just givenWD + → assertWeekDayIsGood givenWD gregDay + (tod, timeZone) ← rfc822Time + let lt = LocalTime gregDay tod + zt = ZonedTime lt timeZone + return zt + +date ∷ Parser Day +date = do day ← read2 + _ ← char ' ' + month ← shortMonthNameP + _ ← char ' ' + year ← read4 + _ ← char ' ' + assertGregorianDateIsGood year month day + +toAsciiBuilder ∷ ZonedTime → AsciiBuilder +toAsciiBuilder zonedTime = let localTime = zonedTimeToLocalTime zonedTime timeZone = zonedTimeZone zonedTime (year, month, day) = toGregorian (localDay localTime) (_, _, week) = toWeekDate (localDay localTime) timeOfDay = localTimeOfDay localTime in - concat [ shortWeekDayName week - , ", " - , show2 day - , " " - , shortMonthName month - , " " - , show4 year - , " " - , show2 (todHour timeOfDay) - , ":" - , show2 (todMin timeOfDay) - , ":" - , show2 (floor (todSec timeOfDay)) - , " " - , showRFC822TimeZone timeZone - ] + shortWeekDayName week + ⊕ A.toAsciiBuilder ", " + ⊕ show2 day + ⊕ A.toAsciiBuilder " " + ⊕ shortMonthName month + ⊕ A.toAsciiBuilder " " + ⊕ show4 year + ⊕ A.toAsciiBuilder " " + ⊕ show2 (todHour timeOfDay) + ⊕ A.toAsciiBuilder ":" + ⊕ show2 (todMin timeOfDay) + ⊕ A.toAsciiBuilder ":" + ⊕ show2 (floor (todSec timeOfDay) ∷ Int) + ⊕ A.toAsciiBuilder " " + ⊕ untag (cs timeZone ∷ Tagged RFC822 AsciiBuilder) --- |Parse an RFC 1123 date and time string. When the string can't be --- parsed, it returns 'Nothing'. -parse :: String -> Maybe ZonedTime -parse src = case P.parse p "" src of - Right zt -> Just zt - Left _ -> Nothing - where - p = do zt <- rfc1123DateAndTime - _ <- P.eof - return zt +deriveAttempts [ ([t| ZonedTime |], [t| Tagged RFC1123 Ascii |]) + , ([t| ZonedTime |], [t| Tagged RFC1123 AsciiBuilder |]) + ]