module Data.Time.HTTP.Common
( shortWeekDayName
, shortWeekDayNameP
, longWeekDayName
, longWeekDayNameP
, shortMonthName
, shortMonthNameP
, longMonthName
, longMonthNameP
, show2
, show4
, read2
, read4
, show4digitsTZ
, read4digitsTZ
, assertWeekDayIsGood
, assertGregorianDateIsGood
, assertTimeOfDayIsGood
)
where
import Control.Monad
import Data.Fixed
import Data.Time
import Data.Time.Calendar.WeekDate
import Text.Parsec
shortWeekDayName :: Int -> String
shortWeekDayName 1 = "Mon"
shortWeekDayName 2 = "Tue"
shortWeekDayName 3 = "Wed"
shortWeekDayName 4 = "Thu"
shortWeekDayName 5 = "Fri"
shortWeekDayName 6 = "Sat"
shortWeekDayName 7 = "Sun"
shortWeekDayName n = error ("shortWeekDayName: unknown day number: " ++ show n)
shortWeekDayNameP :: Stream s m Char => ParsecT s u m Int
shortWeekDayNameP
= choice [ string "Mon" >> return 1
, char 'T'
>> choice [ string "ue" >> return 2
, string "hu" >> return 4
]
, string "Wed" >> return 3
, string "Fri" >> return 5
, char 'S'
>> choice [ string "at" >> return 6
, string "un" >> return 7
]
]
longWeekDayName :: Int -> String
longWeekDayName 1 = "Monday"
longWeekDayName 2 = "Tuesday"
longWeekDayName 3 = "Wednesday"
longWeekDayName 4 = "Thursday"
longWeekDayName 5 = "Friday"
longWeekDayName 6 = "Saturday"
longWeekDayName 7 = "Sunday"
longWeekDayNameP :: Stream s m Char => ParsecT s u m Int
longWeekDayNameP
= choice [ string "Monday" >> return 1
, char 'T'
>> choice [ string "uesday" >> return 2
, string "hursday" >> return 4
]
, string "Wednesday" >> return 3
, string "Friday" >> return 5
, char 'S'
>> choice [ string "aturday" >> return 6
, string "unday" >> return 7
]
]
shortMonthName :: Int -> String
shortMonthName 1 = "Jan"
shortMonthName 2 = "Feb"
shortMonthName 3 = "Mar"
shortMonthName 4 = "Apr"
shortMonthName 5 = "May"
shortMonthName 6 = "Jun"
shortMonthName 7 = "Jul"
shortMonthName 8 = "Aug"
shortMonthName 9 = "Sep"
shortMonthName 10 = "Oct"
shortMonthName 11 = "Nov"
shortMonthName 12 = "Dec"
shortMonthName n = error ("shortMonthName: unknown month number: " ++ show n)
shortMonthNameP :: Stream s m Char => ParsecT s u m Int
shortMonthNameP
= choice [ char 'J'
>> choice [ string "an" >> return 1
, char 'u'
>> choice [ char 'n' >> return 6
, char 'l' >> return 7
]
]
, string "Feb" >> return 2
, string "Ma"
>> choice [ char 'r' >> return 3
, char 'y' >> return 5
]
, char 'A'
>> choice [ string "pr" >> return 4
, string "ug" >> return 8
]
, string "Sep" >> return 9
, string "Oct" >> return 10
, string "Nov" >> return 11
, string "Dec" >> return 12
]
longMonthName :: Int -> String
longMonthName 1 = "January"
longMonthName 2 = "February"
longMonthName 3 = "March"
longMonthName 4 = "April"
longMonthName 5 = "May"
longMonthName 6 = "June"
longMonthName 7 = "July"
longMonthName 8 = "August"
longMonthName 9 = "September"
longMonthName 10 = "October"
longMonthName 11 = "November"
longMonthName 12 = "December"
longMonthName n = error ("longMonthName: unknown month number: " ++ show n)
longMonthNameP :: Stream s m Char => ParsecT s u m Int
longMonthNameP
= choice [ char 'J'
>> choice [ string "anuary" >> return 1
, char 'u'
>> choice [ string "ne" >> return 6
, string "ly" >> return 7
]
]
, string "February" >> return 2
, string "Ma"
>> choice [ string "rch" >> return 3
, char 'y' >> return 5
]
, char 'A'
>> choice [ string "pril" >> return 4
, string "ugust" >> return 8
]
, string "September" >> return 9
, string "October" >> return 10
, string "November" >> return 11
, string "December" >> return 12
]
show4 :: Integral i => i -> String
show4 i
| i >= 0 && i < 10 = "000" ++ show i
| i >= 0 && i < 100 = "00" ++ show i
| i >= 0 && i < 1000 = '0' : show i
| i >= 0 && i < 10000 = show i
| otherwise = error ("show4: the integer i must satisfy 0 <= i < 10000: " ++ show i)
show2 :: Integral i => i -> String
show2 i
| i >= 0 && i < 10 = '0' : show i
| i >= 0 && i < 100 = show i
| otherwise = error ("show2: the integer i must satisfy 0 <= i < 100: " ++ show i)
read4 :: (Stream s m Char, Num n) => ParsecT s u m n
read4 = do n1 <- digit'
n2 <- digit'
n3 <- digit'
n4 <- digit'
return (n1 * 1000 + n2 * 100 + n3 * 10 + n4)
read2 :: (Stream s m Char, Num n) => ParsecT s u m n
read2 = do n1 <- digit'
n2 <- digit'
return (n1 * 10 + n2)
digit' :: (Stream s m Char, Num n) => ParsecT s u m n
digit' = liftM fromC digit
fromC :: Num n => Char -> n
fromC '0' = 0
fromC '1' = 1
fromC '2' = 2
fromC '3' = 3
fromC '4' = 4
fromC '5' = 5
fromC '6' = 6
fromC '7' = 7
fromC '8' = 8
fromC '9' = 9
fromC _ = undefined
show4digitsTZ :: TimeZone -> String
show4digitsTZ tz
= case timeZoneMinutes tz of
offset | offset < 0 -> '-' : showTZ' (negate offset)
| otherwise -> '+' : showTZ' offset
where
showTZ' offset
= let h = offset `div` 60
m = offset h * 60
in
show2 h ++ show2 m
read4digitsTZ :: Stream s m Char => ParsecT s u m TimeZone
read4digitsTZ
= 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
assertWeekDayIsGood :: Stream s m t => Int -> Day -> ParsecT s u m ()
assertWeekDayIsGood givenWD gregDay
= let (_, _, correctWD ) = toWeekDate gregDay
(year, month, day) = toGregorian gregDay
in
unless (givenWD == correctWD)
$ fail
$ concat [ "Gregorian day "
, show year
, "-"
, show month
, "-"
, show day
, " is "
, longWeekDayName correctWD
, ", not "
, longWeekDayName givenWD
]
assertGregorianDateIsGood :: Stream s m t => Integer -> Int -> Int -> ParsecT s u m Day
assertGregorianDateIsGood year month day
= case fromGregorianValid year month day of
Nothing
-> fail $ concat [ "Invalid gregorian day: "
, show year
, "-"
, show month
, "-"
, show day
]
Just gregDay
-> return gregDay
assertTimeOfDayIsGood :: Stream s m t => Int -> Int -> Pico -> ParsecT s u m TimeOfDay
assertTimeOfDayIsGood hour minute second
= case makeTimeOfDayValid hour minute second of
Nothing
-> fail $ concat [ "Invalid time of day: "
, show hour
, ":"
, show minute
, ":"
, showFixed True second
]
Just tod
-> return tod