on master help sign in
Fix utc offset parsing

As I understand ISO 8601:2004, ±HHMM is not a valid syntax for specifying a UTC offset in the context we are using it. Only ±HH and ±HH:MM are valid in the extended ISO 8601 formats. I probably would weakly prefer to not accept ±HHMM, however, because the the ToJSON ZonedTime instance has been emitting this syntax since aeson version 0.6.1.0 released on 2012-12-14, our hands may well be tied on this matter. I can only hope that the older FromJSON instances will also accept ±HH and ±HH:MM, so that we can fix the emitted syntax with minimal disruption, but knowing the time library, this probably is not the case.

commit6b8acde7095fe113b85c45255d5fa538d5741668 authorLeon P Smith <leon@melding-monads.com> dateTue 21 Jul 2015, 02:05 (11 years ago) parent4ff35e4
2 files changed+17−14
Data/Aeson/Parser/Time.hs+15−12 tests/UnitTests.hs+2−2
Data/Aeson/Parser/Time.hs+15−12
@@ -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
tests/UnitTests.hs+2−2
@@ -102,8 +102,8 @@ utcTimeGood = do
102102 assertEqual "utctime" (parseWithRead "%FT%T%QZ" ts2) t2
103103 assertEqual "utctime" (parseWithRead "%F %T%QZ" ts3) t3
104104 assertEqual "utctime" (parseWithRead "%F %T%QZ" ts4) t4
105− -- timezones. Both +HHMM and +HH:MM are allowed for timezone offset
106− let ts5 = "2015-01-01T12:30:00.00+0000" :: LT.Text
105+ -- offsets. ±HH, ±HHMM, and ±HH:MM are allowed for utc offset
106+ let ts5 = "2015-01-01T12:30:00.00+00" :: LT.Text
107107 let ts6 = "2015-01-01T12:30:00.00+01:15" :: LT.Text
108108 let ts7 = "2015-01-01T12:30:00.00-0200" :: LT.Text
109109 let ts8 = "2015-01-01T22:00:00.00-03:00" :: LT.Text