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
20 -- |Parse RFC 733 date and time strings.
21 rfc733DateAndTime ∷ Parser ZonedTime
22 rfc733DateAndTime = dateTime
24 dateTime ∷ Parser ZonedTime
25 dateTime = do weekDay ← optionMaybe $
26 do w ← longWeekDayNameP
36 → assertWeekDayIsGood givenWD gregDay
37 (tod, timeZone) ← time
38 let lt = LocalTime gregDay tod
39 zt = ZonedTime lt timeZone
44 _ ← char '-' <|> char ' '
45 month ← try longMonthNameP
48 _ ← char '-' <|> char ' '
53 assertGregorianDateIsGood year month day
55 time ∷ Parser (TimeOfDay, TimeZone)
57 _ ← char '-' <|> char ' '
61 hms ∷ Parser TimeOfDay
63 _ ← optional (char ':')
66 do _ ← optional (char ':')
68 assertTimeOfDayIsGood hour minute second
70 zone ∷ Parser TimeZone
71 zone = choice [ string "GMT" *> return (TimeZone 0 False "GMT")
73 *> choice [ string "ST" *> return (TimeZone ((-3) * 60 - 30) False "NST")
74 , return (TimeZone (1 * 60) False "N")
77 *> choice [ string "ST" *> return (TimeZone ((-4) * 60) False "AST")
78 , string "DT" *> return (TimeZone ((-3) * 60) False "AST")
79 , return (TimeZone ((-1) * 60) False "A")
82 *> choice [ string "ST" *> return (TimeZone ((-5) * 60) False "EST")
83 , string "DT" *> return (TimeZone ((-4) * 60) True "EDT")
86 *> choice [ string "ST" *> return (TimeZone ((-6) * 60) False "CST")
87 , string "DT" *> return (TimeZone ((-5) * 60) True "CDT")
90 *> choice [ string "ST" *> return (TimeZone ((-7) * 60) False "MST")
91 , string "DT" *> return (TimeZone ((-6) * 60) True "MDT")
92 , return (TimeZone ((-12) * 60) False "M")
95 *> choice [ string "ST" *> return (TimeZone ((-8) * 60) False "PST")
96 , string "DT" *> return (TimeZone ((-7) * 60) True "PDT")
99 *> choice [ string "ST" *> return (TimeZone ((-9) * 60) False "YST")
100 , string "DT" *> return (TimeZone ((-8) * 60) True "YDT")
101 , return (TimeZone ( 12 * 60) False "Y")
104 *> choice [ string "ST" *> return (TimeZone ((-10) * 60) False "HST")
105 , string "DT" *> return (TimeZone (( -9) * 60) True "HDT")
108 *> choice [ string "ST" *> return (TimeZone ((-11) * 60) False "BST")
109 , string "DT" *> return (TimeZone ((-10) * 60) True "BDT")
111 , char 'Z' *> return (TimeZone 0 False "Z")
115 -- |Convert a 'ZonedTime' to RFC 733 date and time string.
116 toAsciiBuilder ∷ ZonedTime → AsciiBuilder
117 toAsciiBuilder zonedTime
118 = let localTime = zonedTimeToLocalTime zonedTime
119 timeZone = zonedTimeZone zonedTime
120 (year, month, day) = toGregorian (localDay localTime)
121 (_, _, week) = toWeekDate (localDay localTime)
122 timeOfDay = localTimeOfDay localTime
125 ⊕ A.toAsciiBuilder ", "
127 ⊕ A.toAsciiBuilder "-"
128 ⊕ shortMonthName month
129 ⊕ A.toAsciiBuilder "-"
131 ⊕ A.toAsciiBuilder " "
132 ⊕ show2 (todHour timeOfDay)
133 ⊕ A.toAsciiBuilder ":"
134 ⊕ show2 (todMin timeOfDay)
135 ⊕ A.toAsciiBuilder ":"
136 ⊕ show2 (floor (todSec timeOfDay) ∷ Int)
137 ⊕ A.toAsciiBuilder "-"
138 ⊕ show4digitsTZ timeZone