{-# 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