@@ -1,4 +1,4 @@
1−{-# LANGUAGE ScopedTypeVariables #-}
1+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
22
33module Data.Aeson.Parser.Time
44 (
@@ -17,9 +17,10 @@ import Data.Bits ((.&.))
1717import Data.Char (ord)
1818import Data.Fixed (Pico)
1919import Data.Int (Int64)
20+import Data.Maybe (fromMaybe)
2021import Data.Text (Text)
2122import Data.Time.Calendar (Day, fromGregorianValid)
22−import Data.Time.Clock (UTCTime)
23+import Data.Time.Clock (UTCTime(..))
2324import qualified Data.Aeson.Types.Internal as Aeson
2425import qualified Data.Text as T
2526import qualified Data.Time.LocalTime as Local
@@ -64,22 +65,26 @@ pico = do
6465 return $! fromIntegral w + fromIntegral f / 10 ^ T.length t
6566 _ -> return $! fromIntegral w
6667
67−timeZone :: Parser Local.TimeZone
68+timeZone :: Parser (Maybe Local.TimeZone)
6869timeZone = do
6970 let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
7071 maybeSkip ' '
7172 ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
7273 if ch == 'Z'
73− then return (Local.TimeZone 0 False "")
74+ then return Nothing
7475 else do
7576 h0 <- twoDigits
7677 m <- maybeSkip ':' *> twoDigits
7778 let h | ch == '-' = negate h0
7879 | otherwise = h0
79− off = h * 60 + m
80− if off < -720 || off > 840 || m > 59
81− then fail "invalid time zone offset"
82− else return $! Local.minutesToTimeZone off
80+ case h * 60 + m of
81+ off | off == 0 ->
82+ return Nothing
83+ | off < -720 || off > 840 || m > 59 ->
84+ fail "invalid time zone offset"
85+ | otherwise ->
86+ let !tz = Local.minutesToTimeZone off
87+ in return (Just tz)
8388
8489localTime :: Parser Local.LocalTime
8590localTime = Local.LocalTime <$> day <* daySep <*> timeOfDay
@@ -87,9 +92,15 @@ localTime = Local.LocalTime <$> day <* daySep <*> timeOfDay
8792
8893utcTime :: Parser UTCTime
8994utcTime = do
90− lt <- localTime
91− tz <- timeZone
92− return $! Local.localTimeToUTC tz lt
95+ lt@(Local.LocalTime d t) <- localTime
96+ mtz <- timeZone
97+ case mtz of
98+ Nothing -> let !tt = Local.timeOfDayToTime t
99+ in return (UTCTime d tt)
100+ Just tz -> return $! Local.localTimeToUTC tz lt
93101
94102zonedTime :: Parser Local.ZonedTime
95−zonedTime = Local.ZonedTime <$> localTime <*> timeZone
103+zonedTime = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
104+
105+utc :: Local.TimeZone
106+utc = Local.TimeZone 0 False ""