5 -- |Internal functions for "Data.Time.RFC733".
6 module Data.Time.RFC733.Internal
11 import Data.Ascii (AsciiBuilder)
12 import qualified Data.Ascii as A
13 import Control.Applicative
14 import Data.Attoparsec.Char8
15 import Data.Monoid.Unicode
17 import Data.Time.Calendar.WeekDate
18 import Data.Time.HTTP.Common
19 import Data.Time.RFC822.Internal hiding (toAsciiBuilder)
21 -- |Parse RFC 733 date and time strings.
22 rfc733DateAndTime ∷ Parser ZonedTime
23 rfc733DateAndTime = dateTime
25 dateTime ∷ Parser ZonedTime
26 dateTime = do weekDay ← optionMaybe $
27 do w ← longWeekDayNameP
37 → assertWeekDayIsGood givenWD gregDay
38 (tod, timeZone) ← time
39 let lt = LocalTime gregDay tod
40 zt = ZonedTime lt timeZone
45 _ ← char '-' <|> char ' '
46 month ← try longMonthNameP
49 _ ← char '-' <|> char ' '
54 assertGregorianDateIsGood year month day
56 time ∷ Parser (TimeOfDay, TimeZone)
58 _ ← char '-' <|> char ' '
62 hms ∷ Parser TimeOfDay
64 _ ← optional (char ':')
67 do _ ← optional (char ':')
69 assertTimeOfDayIsGood hour minute second
71 zone ∷ Parser TimeZone
72 zone = choice [ string "GMT" *> return (TimeZone 0 False "GMT")
74 *> choice [ string "ST" *> return (TimeZone ((-3) * 60 - 30) False "NST")
75 , return (TimeZone (1 * 60) False "N")
78 *> choice [ string "ST" *> return (TimeZone ((-4) * 60) False "AST")
79 , string "DT" *> return (TimeZone ((-3) * 60) False "AST")
80 , return (TimeZone ((-1) * 60) False "A")
83 *> choice [ string "ST" *> return (TimeZone ((-5) * 60) False "EST")
84 , string "DT" *> return (TimeZone ((-4) * 60) True "EDT")
87 *> choice [ string "ST" *> return (TimeZone ((-6) * 60) False "CST")
88 , string "DT" *> return (TimeZone ((-5) * 60) True "CDT")
91 *> choice [ string "ST" *> return (TimeZone ((-7) * 60) False "MST")
92 , string "DT" *> return (TimeZone ((-6) * 60) True "MDT")
93 , return (TimeZone ((-12) * 60) False "M")
96 *> choice [ string "ST" *> return (TimeZone ((-8) * 60) False "PST")
97 , string "DT" *> return (TimeZone ((-7) * 60) True "PDT")
100 *> choice [ string "ST" *> return (TimeZone ((-9) * 60) False "YST")
101 , string "DT" *> return (TimeZone ((-8) * 60) True "YDT")
102 , return (TimeZone ( 12 * 60) False "Y")
105 *> choice [ string "ST" *> return (TimeZone ((-10) * 60) False "HST")
106 , string "DT" *> return (TimeZone (( -9) * 60) True "HDT")
109 *> choice [ string "ST" *> return (TimeZone ((-11) * 60) False "BST")
110 , string "DT" *> return (TimeZone ((-10) * 60) True "BDT")
112 , char 'Z' *> return (TimeZone 0 False "Z")
116 -- |Convert a 'ZonedTime' to RFC 733 date and time string.
117 toAsciiBuilder ∷ ZonedTime → AsciiBuilder
118 toAsciiBuilder zonedTime
119 = let localTime = zonedTimeToLocalTime zonedTime
120 timeZone = zonedTimeZone zonedTime
121 (year, month, day) = toGregorian (localDay localTime)
122 (_, _, week) = toWeekDate (localDay localTime)
123 timeOfDay = localTimeOfDay localTime
126 ⊕ A.toAsciiBuilder ", "
128 ⊕ A.toAsciiBuilder "-"
129 ⊕ shortMonthName month
130 ⊕ A.toAsciiBuilder "-"
132 ⊕ A.toAsciiBuilder " "
133 ⊕ show2 (todHour timeOfDay)
134 ⊕ A.toAsciiBuilder ":"
135 ⊕ show2 (todMin timeOfDay)
136 ⊕ A.toAsciiBuilder ":"
137 ⊕ show2 (floor (todSec timeOfDay) ∷ Int)
138 ⊕ A.toAsciiBuilder " "
139 ⊕ showRFC822TimeZone timeZone