{-# OPTIONS_HADDOCK prune #-}

-- |This module provides functions to parse and format RFC 822 date
-- and time formats.
--
-- The syntax is as follows:
--
-- > date-time   ::= [ day-of-week ", " ] date SP time SP zone
-- > day-of-week ::= "Mon" | "Tue" | "Wed" | "Thu"
-- >               | "Fri" | "Sat" | "Sun"
-- > date        ::= day SP month SP year
-- > day         ::= 2DIGIT
-- > year        ::= 2DIGIT             ; Yes, only 2 digits.
-- > month       ::= "Jan" | "Feb" | "Mar" | "Apr"
-- >               | "May" | "Jun" | "Jul" | "Aug"
-- >               | "Sep" | "Oct" | "Nov" | "Dec"
-- > time        ::= hour ":" minute [ ":" second ]
-- > hour        ::= 2DIGIT
-- > minute      ::= 2DIGIT
-- > second      ::= 2DIGIT
-- > zone        ::= "UT"  | "GMT"      ; Universal Time
-- >               | "EST" | "EDT"      ; Eastern : -5 / -4
-- >               | "CST" | "CDT"      ; Central : -6 / -5
-- >               | "MST" | "MDT"      ; Mountain: -7 / -6
-- >               | "PST" | "PDT"      ; Pacific : -8 / -7
-- >               | "Z"                ; UT
-- >               | "A"                ;  -1
-- >               | "M"                ; -12
-- >               | "N"                ;  +1
-- >               | "Y"                ; +12
-- >               | ("+" | "-") 4DIGIT ; Local diff: HHMM
module Data.Time.RFC822
    ( format
    , parse

    -- private
    , showRFC822TimeZone
    )
    where

import qualified Text.Parsec as P

import Data.Time
import Data.Time.Calendar.WeekDate
import Data.Time.HTTP.Common
import Data.Time.RFC822.Parsec

-- |Format a 'ZonedTime' in RFC 822.
format :: ZonedTime -> String
format 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
               , " "
               , show2 (year `mod` 100)
               , " "
               , show2 (todHour timeOfDay)
               , ":"
               , show2 (todMin timeOfDay)
               , ":"
               , show2 (floor (todSec timeOfDay))
               , " "
               , showRFC822TimeZone timeZone
               ]

showRFC822TimeZone :: TimeZone -> String
showRFC822TimeZone tz
    | timeZoneMinutes tz == 0 = "GMT"
    | otherwise               = show4digitsTZ tz

-- |Parse an RFC 822 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 <- rfc822DateAndTime
             _  <- P.eof
             return zt