    {-# LANGUAGE CPP                #-}
    {-# LANGUAGE DeriveDataTypeable #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Aeson.Extra.Time
    -- Copyright   :  (C) 2015-2016 Oleg Grenrus
    -- License     :  BSD3
    -- Maintainer  :  Oleg Grenrus <oleg.grenrus@iki.fi>
    --
    -- Time tools
    module Data.Aeson.Extra.Time (
        U(..),
        Z(..),
        )where

    import Prelude        ()
    import Prelude.Compat

    import Data.Aeson.Compat
    import Data.Time         (UTCTime, ZonedTime)
    import Data.Typeable     (Typeable)

    #if !MIN_VERSION_aeson (0,10,0)
    import Data.Text         (Text)

    #if !MIN_VERSION_aeson_compat(0,3,5)
    import           Data.Aeson.Types (Parser)
    #endif

    import qualified Data.Time.Parsers as TimeParsers
    import qualified Text.Parsec       as Parsec
    #endif

    -- | A type to parse 'UTCTime'
    --
    -- 'FromJSON' instance accepts for example:
    --
    -- @
    -- 2015-09-07T08:16:40.807Z
    -- 2015-09-07 11:16:40.807 +03:00
    -- @
    --
    -- Latter format is accepted by @aeson@ staring from version @0.10.0.0@.
    --
    -- See <https://github.com/bos/aeson/blob/4667ef1029a373cf4510f7deca147c357c6d8947/Data/Aeson/Parser/Time.hs#L150>
    --
    -- /Since: aeson-extra-0.2.2.0/
    newtype U = U { U -> UTCTime
    getU :: UTCTime }
      deriving (U -> U -> Bool
    (U -> U -> Bool) -> (U -> U -> Bool) -> Eq U
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: U -> U -> Bool
    $c/= :: U -> U -> Bool
    == :: U -> U -> Bool
    $c== :: U -> U -> Bool
    Eq, Eq U
    Eq U =>
    (U -> U -> Ordering)
    -> (U -> U -> Bool)
    -> (U -> U -> Bool)
    -> (U -> U -> Bool)
    -> (U -> U -> Bool)
    -> (U -> U -> U)
    -> (U -> U -> U)
    -> Ord U
    U -> U -> Bool
    U -> U -> Ordering
    U -> U -> U
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: U -> U -> U
    $cmin :: U -> U -> U
    max :: U -> U -> U
    $cmax :: U -> U -> U
    >= :: U -> U -> Bool
    $c>= :: U -> U -> Bool
    > :: U -> U -> Bool
    $c> :: U -> U -> Bool
    <= :: U -> U -> Bool
    $c<= :: U -> U -> Bool
    < :: U -> U -> Bool
    $c< :: U -> U -> Bool
    compare :: U -> U -> Ordering
    $ccompare :: U -> U -> Ordering
    $cp1Ord :: Eq U
    Ord, Int -> U -> ShowS
    [U] -> ShowS
    U -> String
    (Int -> U -> ShowS) -> (U -> String) -> ([U] -> ShowS) -> Show U
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [U] -> ShowS
    $cshowList :: [U] -> ShowS
    show :: U -> String
    $cshow :: U -> String
    showsPrec :: Int -> U -> ShowS
    $cshowsPrec :: Int -> U -> ShowS
    Show, ReadPrec [U]
    ReadPrec U
    Int -> ReadS U
    ReadS [U]
    (Int -> ReadS U)
    -> ReadS [U] -> ReadPrec U -> ReadPrec [U] -> Read U
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [U]
    $creadListPrec :: ReadPrec [U]
    readPrec :: ReadPrec U
    $creadPrec :: ReadPrec U
    readList :: ReadS [U]
    $creadList :: ReadS [U]
    readsPrec :: Int -> ReadS U
    $creadsPrec :: Int -> ReadS U
    Read, Typeable)

    instance ToJSON U where
      toJSON :: U -> Value
    toJSON = UTCTime -> Value
    forall a. ToJSON a => a -> Value
    toJSON (UTCTime -> Value) -> (U -> UTCTime) -> U -> Value
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . U -> UTCTime
    getU
    #if MIN_VERSION_aeson (0,10,0)
      toEncoding :: U -> Encoding
    toEncoding = UTCTime -> Encoding
    forall a. ToJSON a => a -> Encoding
    toEncoding (UTCTime -> Encoding) -> (U -> UTCTime) -> U -> Encoding
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . U -> UTCTime
    getU
    #endif

    instance FromJSON U where
    #if MIN_VERSION_aeson (0,10,0)
      parseJSON :: Value -> Parser U
    parseJSON = (UTCTime -> U) -> Parser UTCTime -> Parser U
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap UTCTime -> U
    U (Parser UTCTime -> Parser U)
    -> (Value -> Parser UTCTime) -> Value -> Parser U
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Value -> Parser UTCTime
    forall a. FromJSON a => Value -> Parser a
    parseJSON
    #else
      parseJSON = withText "UTCTime" (fmap U . run TimeParsers.utcTime)
    #endif

    -- | A type to parse 'ZonedTime'
    --
    -- /Since: aeson-extra-0.2.2.0/
    newtype Z = Z { Z -> ZonedTime
    getZ :: ZonedTime }
      deriving (Int -> Z -> ShowS
    [Z] -> ShowS
    Z -> String
    (Int -> Z -> ShowS) -> (Z -> String) -> ([Z] -> ShowS) -> Show Z
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Z] -> ShowS
    $cshowList :: [Z] -> ShowS
    show :: Z -> String
    $cshow :: Z -> String
    showsPrec :: Int -> Z -> ShowS
    $cshowsPrec :: Int -> Z -> ShowS
    Show, ReadPrec [Z]
    ReadPrec Z
    Int -> ReadS Z
    ReadS [Z]
    (Int -> ReadS Z)
    -> ReadS [Z] -> ReadPrec Z -> ReadPrec [Z] -> Read Z
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Z]
    $creadListPrec :: ReadPrec [Z]
    readPrec :: ReadPrec Z
    $creadPrec :: ReadPrec Z
    readList :: ReadS [Z]
    $creadList :: ReadS [Z]
    readsPrec :: Int -> ReadS Z
    $creadsPrec :: Int -> ReadS Z
    Read, Typeable)

    instance ToJSON Z where
      toJSON :: Z -> Value
    toJSON = ZonedTime -> Value
    forall a. ToJSON a => a -> Value
    toJSON (ZonedTime -> Value) -> (Z -> ZonedTime) -> Z -> Value
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Z -> ZonedTime
    getZ
    #if MIN_VERSION_aeson (0,10,0)
      toEncoding :: Z -> Encoding
    toEncoding = ZonedTime -> Encoding
    forall a. ToJSON a => a -> Encoding
    toEncoding (ZonedTime -> Encoding) -> (Z -> ZonedTime) -> Z -> Encoding
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Z -> ZonedTime
    getZ
    #endif

    instance FromJSON Z where
    #if MIN_VERSION_aeson (0,10,0)
      parseJSON :: Value -> Parser Z
    parseJSON = (ZonedTime -> Z) -> Parser ZonedTime -> Parser Z
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ZonedTime -> Z
    Z (Parser ZonedTime -> Parser Z)
    -> (Value -> Parser ZonedTime) -> Value -> Parser Z
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Value -> Parser ZonedTime
    forall a. FromJSON a => Value -> Parser a
    parseJSON
    #else
      parseJSON = withText "ZonedTime" (fmap Z . run TimeParsers.zonedTime)
    #endif

    #if !MIN_VERSION_aeson (0,10,0)
    -- | Run a 'parsers' parser as an aeson parser.
    run :: Parsec.Parsec Text () a -> Text -> Parser a
    run p t = case Parsec.parse (p <* Parsec.eof) "" t of
                Left err -> fail $ "could not parse date: " ++ show err
                Right r  -> return r
    #endif