@@ -113,17 +113,22 @@ timeZone = do
113113 if ch == 'Z'
114114 then return Nothing
115115 else do
116− h0 <- twoDigits
117− m <- maybeSkip ':' *> twoDigits
118− let h | ch == '-' = negate h0
119− | otherwise = h0
120− case h * 60 + m of
121− off | off == 0 ->
116+ h <- twoDigits
117+ mc <- peekChar
118+ m <- case mc of
119+ Just c | c == ':' -> anyChar *> twoDigits
120+ | isDigit c -> twoDigits
121+ _ -> return 0
122+ case () of
123+ _ | h == 0 && m == 0 ->
122124 return Nothing
123− | off < -720 || off > 840 || m > 59 ->
125+ | h > 23 || m > 59 ->
124126 fail "invalid time zone offset"
125− | otherwise ->
126− let !tz = Local.minutesToTimeZone off
127+ | otherwise ->
128+ let !absset = h * 60 + m
129+ !offset | ch == '-' = negate absset
130+ | otherwise = absset
131+ !tz = Local.minutesToTimeZone offset
127132 in return (Just tz)
128133
129134-- | Parse a date and time, of the form @YYYY-MM-DD HH:MM:SS@.
@@ -150,9 +155,7 @@ utcTime = do
150155--
151156-- The first space may instead be a @T@, and the second space is
152157-- optional. The @Z@ represents UTC. The @Z@ may be replaced with a
153−-- time zone offset of the form @+0000@ or @-08:00@, where the first
154−-- two digits are hours, the @:@ is optional and the second two digits
155−-- are minutes.
158+-- time zone offset of the form @±HH@ or @±HH:MM@.
156159zonedTime :: Parser Local.ZonedTime
157160zonedTime = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
158161