    {-# LANGUAGE NoImplicitPrelude #-}

    module Data.Aeson.Parser.Time
        (
          run
        , day
        , localTime
        , timeOfDay
        , timeZone
        , utcTime
        , zonedTime
        ) where

    import Prelude.Compat

    import Data.Attoparsec.Text (Parser)
    import Data.Text (Text)
    import Data.Time.Calendar (Day)
    import Data.Time.Clock (UTCTime(..))
    import qualified Data.Aeson.Types.Internal as Aeson
    import qualified Data.Attoparsec.Text as A
    import qualified Data.Attoparsec.Time as T
    import qualified Data.Time.LocalTime as Local

    -- | Run an attoparsec parser as an aeson parser.
    run :: Parser a -> Text -> Aeson.Parser a
    run :: Parser a -> Text -> Parser a
    run p :: Parser a
    p t :: Text
    t = case Parser a -> Text -> Either String a
    forall a. Parser a -> Text -> Either String a
    A.parseOnly (Parser a
    p Parser a -> Parser Text () -> Parser a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Parser Text ()
    forall t. Chunk t => Parser t ()
    A.endOfInput) Text
    t of
                Left err :: String
    err -> String -> Parser a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> Parser a) -> String -> Parser a
    forall a b. (a -> b) -> a -> b
    $ "could not parse date: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    err
                Right r :: a
    r  -> a -> Parser a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    r

    -- | Parse a date of the form @[+,-]YYYY-MM-DD@.
    day :: Parser Day
    day :: Parser Day
    day = Parser Day
    T.day
    {-# INLINE day #-}

    -- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
    timeOfDay :: Parser Local.TimeOfDay
    timeOfDay :: Parser TimeOfDay
    timeOfDay = Parser TimeOfDay
    T.timeOfDay
    {-# INLINE timeOfDay #-}

    -- | Parse a time zone, and return 'Nothing' if the offset from UTC is
    -- zero. (This makes some speedups possible.)
    timeZone :: Parser (Maybe Local.TimeZone)
    timeZone :: Parser (Maybe TimeZone)
    timeZone = Parser (Maybe TimeZone)
    T.timeZone
    {-# INLINE timeZone #-}

    -- | Parse a date and time, of the form @YYYY-MM-DD HH:MM[:SS[.SSS]]@.
    -- The space may be replaced with a @T@.  The number of seconds is optional
    -- and may be followed by a fractional component.
    localTime :: Parser Local.LocalTime
    localTime :: Parser LocalTime
    localTime = Parser LocalTime
    T.localTime
    {-# INLINE localTime #-}

    -- | Behaves as 'zonedTime', but converts any time zone offset into a
    -- UTC time.
    utcTime :: Parser UTCTime
    utcTime :: Parser UTCTime
    utcTime = Parser UTCTime
    T.utcTime
    {-# INLINE utcTime #-}

    -- | Parse a date with time zone info. Acceptable formats:
    --
    -- @YYYY-MM-DD HH:MM Z@
    -- @YYYY-MM-DD HH:MM:SS Z@
    -- @YYYY-MM-DD HH:MM:SS.SSS Z@
    --
    -- The first space may instead be a @T@, and the second space is
    -- optional.  The @Z@ represents UTC.  The @Z@ may be replaced with a
    -- time zone offset of the form @+0000@ or @-08:00@, where the first
    -- two digits are hours, the @:@ is optional and the second two digits
    -- (also optional) are minutes.
    zonedTime :: Parser Local.ZonedTime
    zonedTime :: Parser ZonedTime
    zonedTime = Parser ZonedTime
    T.zonedTime
    {-# INLINE zonedTime #-}