on master help sign in
WIP
commit8f821b8b68afa6a92842948ca1751fd9562b2273 authorBryan O'Sullivan <bos@serpentine.com> dateFri 17 Jul 2015, 16:55 (11 years ago) parentc156e91
2 files changed+46−30
Data/Aeson/Parser/Time.hs+44−1 Data/Aeson/Types/Instances.hs+2−29
Data/Aeson/Parser/Time.hs+44−1
@@ -1,20 +1,32 @@
1+{-# LANGUAGE CPP #-}
2+
13module Data.Aeson.Parser.Time
24 (
35 day
46 , timeOfDay
57 , timeZone
68 , utcTime
9+ , zonedTime
710 ) where
811
9−import Control.Applicative ((<$>))
12+import Control.Applicative ((<$>), (<|>), empty)
1013import Control.Monad (when, void)
14+import qualified Data.Aeson.Types.Internal as Aeson
1115import Data.Attoparsec.Text as A
16+import Data.Text (Text)
1217import Data.Time.Calendar (Day, fromGregorianValid)
1318import Data.Time.Clock (UTCTime)
19+import Data.Time.Format (parseTime)
1420import qualified Data.Time.LocalTime as Local
1521import qualified Data.Text as T
1622import qualified Data.Text.Read as T
1723
24+#if MIN_VERSION_time(1,5,0)
25+import Data.Time.Format (defaultTimeLocale, dateTimeFmt)
26+#else
27+import System.Locale (defaultTimeLocale, dateTimeFmt)
28+#endif
29+
1830day :: A.Parser Day
1931day = do
2032 y <- decimal <* char '-'
@@ -54,3 +66,34 @@ utcTime = do
5466 lt <- Local.LocalTime <$> day <* daySep <*> timeOfDay
5567 tz <- timeZone
5668 return (Local.localTimeToUTC tz lt)
69+
70+zonedTime :: Text -> Aeson.Parser Local.ZonedTime
71+zonedTime t =
72+ tryFormats alternateFormats
73+ <|> fail "could not parse ECMA-262 ISO-8601 date"
74+ where
75+ tryFormat f =
76+ case parseTime defaultTimeLocale f (T.unpack t) of
77+ Just d -> pure d
78+ Nothing -> empty
79+ tryFormats = foldr1 (<|>) . map tryFormat
80+ alternateFormats =
81+ "%FT%T%QZ" : -- (javascript new Date().toISOString())
82+ "%F %T%Q%z" : -- (postgres)
83+ "%F %T%Q %Z" : -- (time's Show format)
84+ "%FT%T%Q%z" :
85+ "%Y-%mT%T%Q" :
86+ "%Y-%mT%R" :
87+ "%Y-%mT%T" :
88+ "%Y-%mT%T%QZ" :
89+ "%Y-%mT%T%Q%z" :
90+ "%YT%T%Q" :
91+ "%YT%R" :
92+ "%YT%T" :
93+ "%YT%T%QZ" :
94+ "%YT%T%Q%z" :
95+ "%FT%T%Q" :
96+ "%FT%R" :
97+ "%FT%T" :
98+ dateTimeFmt defaultTimeLocale :
99+ []
Data/Aeson/Types/Instances.hs+2−29
@@ -60,6 +60,7 @@ import qualified Data.ByteString.Builder as B
6060import Data.Aeson.Functions
6161import Data.Monoid ((<>), mempty)
6262import Data.Aeson.Encode.Functions (brackets, builder, foldable, list)
63+import qualified Data.Aeson.Parser.Time as Time
6364import Data.Aeson.Types.Class
6465import Data.Aeson.Types.Internal
6566import Data.Scientific (Scientific)
@@ -726,35 +727,7 @@ formatSubseconds :: (FormatTime t) => t -> String
726727formatSubseconds = formatTime defaultTimeLocale "%q"
727728
728729instance FromJSON ZonedTime where
729− parseJSON (String t) =
730− tryFormats alternateFormats
731− <|> fail "could not parse ECMA-262 ISO-8601 date"
732− where
733− tryFormat f =
734− case parseTime defaultTimeLocale f (unpack t) of
735− Just d -> pure d
736− Nothing -> empty
737− tryFormats = foldr1 (<|>) . map tryFormat
738− alternateFormats =
739− "%FT%T%QZ" : -- (javascript new Date().toISOString())
740− "%F %T%Q%z" : -- (postgres)
741− "%F %T%Q %Z" : -- (time's Show format)
742− "%FT%T%Q%z" :
743− "%Y-%mT%T%Q" :
744− "%Y-%mT%R" :
745− "%Y-%mT%T" :
746− "%Y-%mT%T%QZ" :
747− "%Y-%mT%T%Q%z" :
748− "%YT%T%Q" :
749− "%YT%R" :
750− "%YT%T" :
751− "%YT%T%QZ" :
752− "%YT%T%Q%z" :
753− "%FT%T%Q" :
754− "%FT%R" :
755− "%FT%T" :
756− dateTimeFmt defaultTimeLocale :
757− []
730+ parseJSON (String t) = Time.zonedTime t
758731
759732 parseJSON v = typeMismatch "ZonedTime" v
760733