diff options
-rw-r--r-- | TimeUtil.hs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/TimeUtil.hs b/TimeUtil.hs new file mode 100644 index 0000000..a4391e9 --- /dev/null +++ b/TimeUtil.hs | |||
@@ -0,0 +1,88 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | {-# LANGUAGE ViewPatterns #-} | ||
3 | module TimeUtil | ||
4 | ( now | ||
5 | , IsTime(..) | ||
6 | , parseRFC2822 | ||
7 | , printRFC2822 | ||
8 | ) where | ||
9 | |||
10 | import Data.Time.LocalTime | ||
11 | import Data.Time.Format | ||
12 | import Data.Time.Clock | ||
13 | import Data.Time.Clock.POSIX | ||
14 | import System.Locale | ||
15 | import Data.String | ||
16 | import Control.Applicative | ||
17 | import Data.Maybe | ||
18 | import Data.Char | ||
19 | import qualified Data.ByteString.Char8 as S | ||
20 | |||
21 | class IsTime a where | ||
22 | fromZonedTime :: ZonedTime -> a | ||
23 | toZonedTime :: a -> IO ZonedTime | ||
24 | |||
25 | instance IsTime ZonedTime where | ||
26 | fromZonedTime x = x | ||
27 | toZonedTime x = return x | ||
28 | |||
29 | instance IsTime UTCTime where | ||
30 | toZonedTime t = utcToLocalZonedTime t | ||
31 | fromZonedTime zt = zonedTimeToUTC zt | ||
32 | |||
33 | instance IsTime Integer where | ||
34 | toZonedTime t = utcToLocalZonedTime utime | ||
35 | where | ||
36 | utime = posixSecondsToUTCTime (fromIntegral t) | ||
37 | fromZonedTime zt = round $ utcTimeToPOSIXSeconds utime | ||
38 | where | ||
39 | utime = zonedTimeToUTC zt | ||
40 | |||
41 | printRFC2822 :: (IsString b, IsTime a) => a -> IO b | ||
42 | printRFC2822 tm = do | ||
43 | zt@(ZonedTime lt z) <- toZonedTime tm | ||
44 | let rfc2822 = formatTime defaultTimeLocale "%a, %0e %b %Y %T" zt ++ printZone | ||
45 | timeZoneStr = timeZoneOffsetString z | ||
46 | printZone = " " ++ timeZoneStr ++ " (" ++ fromString (show z) ++ ")" | ||
47 | return $ fromString $ rfc2822 | ||
48 | |||
49 | parseRFC2822 :: IsTime b => S.ByteString -> Maybe b | ||
50 | parseRFC2822 str = | ||
51 | case mapMaybe (\f->parseTime defaultTimeLocale f str') formatRFC2822 of | ||
52 | [] -> Nothing | ||
53 | (zt:_) -> Just $ fromZonedTime zt | ||
54 | where | ||
55 | str' = S.unpack stripped | ||
56 | stripped = strip $ str | ||
57 | strip bs = bs3 | ||
58 | where | ||
59 | (_,bs0) = S.span isSpace bs | ||
60 | (bs1,_) = S.spanEnd isSpace bs0 | ||
61 | (bs2,cp) = S.spanEnd (==')') bs1 | ||
62 | bs3 = if S.null cp | ||
63 | then bs2 | ||
64 | else let (op,_) = S.spanEnd (/='(') bs2 | ||
65 | in fst $ S.spanEnd isSpace $ S.init op | ||
66 | formatRFC2822 = [ "%a, %e %b %Y %T GMT" | ||
67 | , "%a, %e %b %Y %T %z" | ||
68 | , "%e %b %Y %T GMT" | ||
69 | , "%e %b %Y %T %z" | ||
70 | , "%a, %e %b %Y %R GMT" | ||
71 | , "%a, %e %b %Y %R %z" | ||
72 | , "%e %b %Y %R GMT" | ||
73 | , "%e %b %Y %R %z" | ||
74 | ] | ||
75 | |||
76 | now :: IO Integer | ||
77 | now = floor <$> Data.Time.Clock.POSIX.getPOSIXTime | ||
78 | |||
79 | {- | ||
80 | main = do | ||
81 | nowtime <- now | ||
82 | printRFC2822 nowtime >>= putStrLn | ||
83 | let test1 = "Thu, 08 May 2014 23:24:47 -0400" | ||
84 | test2 = " Thu, 08 May 2014 23:24:47 -0400 (EDT) " | ||
85 | putStrLn $ show (parseRFC2822 test1 :: Maybe Integer) | ||
86 | putStrLn $ show (parseRFC2822 test2 :: Maybe Integer) | ||
87 | return () | ||
88 | -} | ||