@@ -1,6 +1,8 @@
11{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleContexts, FlexibleInstances,
22 GeneralizedNewtypeDeriving, IncoherentInstances, OverlappingInstances,
3− OverloadedStrings, UndecidableInstances, ViewPatterns #-}
3+ OverloadedStrings, UndecidableInstances, ViewPatterns,
4+ StandaloneDeriving #-}
5+{-# OPTIONS_GHC -fno-warn-orphans #-}
46
57#ifdef GENERICS
68{-# LANGUAGE DefaultSignatures #-}
@@ -39,18 +41,18 @@ module Data.Aeson.Types.Class
3941 , typeMismatch
4042 ) where
4143
42−import Control.Applicative ((<$>), (<*>), pure)
44+import Control.Applicative ((<$>), (<*>), (<|>), pure, empty)
4345import Data.Aeson.Functions
4446import Data.Aeson.Types.Internal
4547import Data.Attoparsec.Char8 (Number(..))
4648import Data.Hashable (Hashable(..))
4749import Data.Int (Int8, Int16, Int32, Int64)
4850import Data.Maybe (fromMaybe)
49−import Data.Monoid (Dual(..), First(..), Last(..))
51+import Data.Monoid (Dual(..), First(..), Last(..), mappend)
5052import Data.Ratio (Ratio)
5153import Data.Text (Text, pack, unpack)
5254import Data.Text.Encoding (encodeUtf8)
53−import Data.Time.Clock (UTCTime)
55+import Data.Time (UTCTime, ZonedTime(..), TimeZone(..))
5456import Data.Time.Format (FormatTime, formatTime, parseTime)
5557import Data.Traversable (traverse)
5658import Data.Typeable (Typeable)
@@ -611,6 +613,37 @@ instance FromJSON DotNetTime where
611613 parseJSON v = typeMismatch "DotNetTime" v
612614 {-# INLINE parseJSON #-}
613615
616+deriving instance Eq ZonedTime
617+
618+instance ToJSON ZonedTime where
619+ toJSON t = String $ pack $ formattedTime
620+ where
621+ formattedTime
622+ | 0 == timeZoneMinutes (zonedTimeZone t) =
623+ formatTime defaultTimeLocale "%FT%T%QZ" t
624+ | otherwise =
625+ formatTime defaultTimeLocale "%FT%T%Q%z" t
626+
627+instance FromJSON ZonedTime where
628+ parseJSON (String t) =
629+ tryFormats alternateFormats
630+ <|> fail "could not parse ECMA-262 ISO-8601 date"
631+ where
632+ tryFormat f =
633+ case parseTime defaultTimeLocale f (unpack t) of
634+ Just d -> pure d
635+ Nothing -> empty
636+ tryFormats = foldr1 (<|>) . map tryFormat
637+ alternateFormats =
638+ distributeList ["%Y", "%Y-%m", "%F"]
639+ ["T%R", "T%T", "T%T%Q", "T%T%QZ", "T%T%Q%z"]
640+
641+ distributeList xs ys =
642+ foldr (\x acc -> acc ++ distribute x ys) [] xs
643+ distribute x = map (mappend x)
644+
645+ parseJSON v = typeMismatch "ZonedTime" v
646+
614647instance ToJSON UTCTime where
615648 toJSON t = String (pack (take 23 str ++ "Z"))
616649 where str = formatTime defaultTimeLocale "%FT%T%Q" t