    {-# LANGUAGE BangPatterns #-}
    {-# LANGUAGE NoImplicitPrelude #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    -- |
    -- Module:      Data.Aeson.Parser.Time
    -- Copyright:   (c) 2015-2016 Bryan O'Sullivan
    -- License:     BSD3
    -- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>
    -- Stability:   experimental
    -- Portability: portable
    --
    -- Parsers for parsing dates and times.

    module Data.Attoparsec.Time
        (
          day
        , localTime
        , timeOfDay
        , timeZone
        , utcTime
        , zonedTime
        , year
        , month
        , quarter
        ) where

    import Prelude.Compat

    import Control.Applicative ((<|>))
    import Control.Monad (void, when)
    import Data.Attoparsec.Text (Parser, char, digit, option, anyChar, peekChar, peekChar', takeWhile1, satisfy)
    import Data.Attoparsec.Time.Internal (toPico)
    import Data.Bits ((.&.))
    import Data.Char (isDigit, ord)
    import Data.Fixed (Pico)
    import Data.Int (Int64)
    import Data.Maybe (fromMaybe)
    import Data.Time.Calendar (Day, fromGregorianValid)
    import Data.Time.Calendar.Compat (Year)
    import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..), fromYearQuarter)
    import Data.Time.Calendar.Month.Compat (Month, fromYearMonthValid)
    import Data.Time.Clock (UTCTime(..))
    import qualified Data.Text as T
    import qualified Data.Time.LocalTime as Local

    -- | Parse a date of the form @[+,-]YYYY-MM-DD@.
    --
    -- The year must contain at least 4 digits, to avoid the Y2K problem:
    -- a two-digit year @YY@ may mean @YY@, @19YY@, or @20YY@, and we make it
    -- an error to prevent the ambiguity.
    -- Years from @0000@ to @0999@ must thus be zero-padded.
    -- The year may have more than 4 digits.
    day :: Parser Day
    day :: Parser Day
    day = do
      Integer -> Integer
    absOrNeg <- Integer -> Integer
    forall a. Num a => a -> a
    negate (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '-' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Integer -> Integer
    forall a. a -> a
    id (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '+' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> (Integer -> Integer) -> Parser Text (Integer -> Integer)
    forall a. a -> Parser Text a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Integer -> Integer
    forall a. a -> a
    id
      Integer
    y <- (Parser Integer
    year Parser Integer -> Parser Text Char -> Parser Integer
    forall a b. Parser Text a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> Parser Text Char
    char Char
    '-') Parser Integer -> Parser Integer -> Parser Integer
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Integer
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "date must be of form [+,-]YYYY-MM-DD"
      Int
    m <- (Parser Int
    twoDigits Parser Int -> Parser Text Char -> Parser Int
    forall a b. Parser Text a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> Parser Text Char
    char Char
    '-') Parser Int -> Parser Int -> Parser Int
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Int
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "date must be of form [+,-]YYYY-MM-DD"
      Int
    d <- Parser Int
    twoDigits Parser Int -> Parser Int -> Parser Int
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Int
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "date must be of form [+,-]YYYY-MM-DD"
      Parser Day -> (Day -> Parser Day) -> Maybe Day -> Parser Day
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (String -> Parser Day
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "invalid date") Day -> Parser Day
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Integer -> Int -> Int -> Maybe Day
    fromGregorianValid (Integer -> Integer
    absOrNeg Integer
    y) Int
    m Int
    d)

    -- | Parse a month of the form @[+,-]YYYY-MM@.
    --
    -- See also 'day' for details about the year format.
    month :: Parser Month
    month :: Parser Month
    month = do
      Integer -> Integer
    absOrNeg <- Integer -> Integer
    forall a. Num a => a -> a
    negate (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '-' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Integer -> Integer
    forall a. a -> a
    id (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '+' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> (Integer -> Integer) -> Parser Text (Integer -> Integer)
    forall a. a -> Parser Text a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Integer -> Integer
    forall a. a -> a
    id
      Integer
    y <- (Parser Integer
    year Parser Integer -> Parser Text Char -> Parser Integer
    forall a b. Parser Text a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> Parser Text Char
    char Char
    '-') Parser Integer -> Parser Integer -> Parser Integer
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Integer
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "month must be of form [+,-]YYYY-MM"
      Int
    m <- Parser Int
    twoDigits Parser Int -> Parser Int -> Parser Int
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Int
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "month must be of form [+,-]YYYY-MM"
      Parser Month
    -> (Month -> Parser Month) -> Maybe Month -> Parser Month
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (String -> Parser Month
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "invalid month") Month -> Parser Month
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Integer -> Int -> Maybe Month
    fromYearMonthValid (Integer -> Integer
    absOrNeg Integer
    y) Int
    m)

    -- | Parse a quarter of the form @[+,-]YYYY-QN@.
    --
    -- See also 'day' for details about the year format.
    quarter :: Parser Quarter
    quarter :: Parser Quarter
    quarter = do
      Integer -> Integer
    absOrNeg <- Integer -> Integer
    forall a. Num a => a -> a
    negate (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '-' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Integer -> Integer
    forall a. a -> a
    id (Integer -> Integer)
    -> Parser Text Char -> Parser Text (Integer -> Integer)
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '+' Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    -> Parser Text (Integer -> Integer)
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> (Integer -> Integer) -> Parser Text (Integer -> Integer)
    forall a. a -> Parser Text a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Integer -> Integer
    forall a. a -> a
    id
      Integer
    y <- (Parser Integer
    year Parser Integer -> Parser Text Char -> Parser Integer
    forall a b. Parser Text a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> Parser Text Char
    char Char
    '-') Parser Integer -> Parser Integer -> Parser Integer
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> Parser Integer
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "month must be of form [+,-]YYYY-MM"
      Char
    _ <- Char -> Parser Text Char
    char Char
    'q' Parser Text Char -> Parser Text Char -> Parser Text Char
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Char -> Parser Text Char
    char Char
    'Q'
      QuarterOfYear
    q <- Parser Text QuarterOfYear
    parseQ
      Quarter -> Parser Quarter
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Quarter -> Parser Quarter) -> Quarter -> Parser Quarter
    forall a b. (a -> b) -> a -> b
    $! Integer -> QuarterOfYear -> Quarter
    fromYearQuarter (Integer -> Integer
    absOrNeg Integer
    y) QuarterOfYear
    q
      where
        parseQ :: Parser Text QuarterOfYear
    parseQ = QuarterOfYear
    Q1 QuarterOfYear -> Parser Text Char -> Parser Text QuarterOfYear
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '1'
          Parser Text QuarterOfYear
    -> Parser Text QuarterOfYear -> Parser Text QuarterOfYear
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> QuarterOfYear
    Q2 QuarterOfYear -> Parser Text Char -> Parser Text QuarterOfYear
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '2'
          Parser Text QuarterOfYear
    -> Parser Text QuarterOfYear -> Parser Text QuarterOfYear
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> QuarterOfYear
    Q3 QuarterOfYear -> Parser Text Char -> Parser Text QuarterOfYear
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '3'
          Parser Text QuarterOfYear
    -> Parser Text QuarterOfYear -> Parser Text QuarterOfYear
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> QuarterOfYear
    Q4 QuarterOfYear -> Parser Text Char -> Parser Text QuarterOfYear
    forall a b. a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ Char -> Parser Text Char
    char Char
    '4'

    -- | Parse a year @YYYY@, with at least 4 digits. Does not include any sign.
    --
    -- Note: 'Year' is a type synonym for 'Integer'.
    --
    -- @since 1.1.0.0
    year :: Parser Year
    year :: Parser Integer
    year = do
      Text
    ds <- (Char -> Bool) -> Parser Text
    takeWhile1 Char -> Bool
    isDigit
      if Text -> Int
    T.length Text
    ds Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    4 then
        String -> Parser Integer
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "expected year with at least 4 digits"
      else
        Integer -> Parser Integer
    forall a. a -> Parser Text a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Text -> Integer
    txtToInteger Text
    ds)

    -- | Parse a two-digit integer (e.g. day of month, hour).
    twoDigits :: Parser Int
    twoDigits :: Parser Int
    twoDigits = do
      Char
    a <- Parser Text Char
    digit
      Char
    b <- Parser Text Char
    digit
      let c2d :: Char -> Int
    c2d Char
    c = Char -> Int
    ord Char
    c Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    15
      Int -> Parser Int
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> Parser Int) -> Int -> Parser Int
    forall a b. (a -> b) -> a -> b
    $! Char -> Int
    c2d Char
    a Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    10 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Char -> Int
    c2d Char
    b

    -- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
    timeOfDay :: Parser Local.TimeOfDay
    timeOfDay :: Parser TimeOfDay
    timeOfDay = do
      Int
    h <- Parser Int
    twoDigits
      Int
    m <- Char -> Parser Text Char
    char Char
    ':' Parser Text Char -> Parser Int -> Parser Int
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Parser Int
    twoDigits
      Pico
    s <- Pico -> Parser Text Pico -> Parser Text Pico
    forall (f :: * -> *) a. Alternative f => a -> f a -> f a
    option Pico
    0 (Char -> Parser Text Char
    char Char
    ':' Parser Text Char -> Parser Text Pico -> Parser Text Pico
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Parser Text Pico
    seconds)
      if Int
    h Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    24 Bool -> Bool -> Bool
    && Int
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    60 Bool -> Bool -> Bool
    && Pico
    s Pico -> Pico -> Bool
    forall a. Ord a => a -> a -> Bool
    < Pico
    61
        then TimeOfDay -> Parser TimeOfDay
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> Int -> Pico -> TimeOfDay
    Local.TimeOfDay Int
    h Int
    m Pico
    s)
        else String -> Parser TimeOfDay
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "invalid time"

    data T = T {-# UNPACK #-} !Int {-# UNPACK #-} !Int64

    -- | Parse a count of seconds, with the integer part being two digits
    -- long.
    seconds :: Parser Pico
    seconds :: Parser Text Pico
    seconds = do
      Int
    real <- Parser Int
    twoDigits
      Maybe Char
    mc <- Parser (Maybe Char)
    peekChar
      case Maybe Char
    mc of
        Just Char
    '.' -> do
          Text
    t <- Parser Text Char
    anyChar Parser Text Char -> Parser Text -> Parser Text
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> (Char -> Bool) -> Parser Text
    takeWhile1 Char -> Bool
    isDigit
          Pico -> Parser Text Pico
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Pico -> Parser Text Pico) -> Pico -> Parser Text Pico
    forall a b. (a -> b) -> a -> b
    $! Int -> Text -> Pico
    forall {p}. Integral p => p -> Text -> Pico
    parsePicos Int
    real Text
    t
        Maybe Char
    _ -> Pico -> Parser Text Pico
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Pico -> Parser Text Pico) -> Pico -> Parser Text Pico
    forall a b. (a -> b) -> a -> b
    $! Int -> Pico
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    real
     where
      parsePicos :: p -> Text -> Pico
    parsePicos p
    a0 Text
    t = Integer -> Pico
    toPico (Int64 -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int64
    t' Int64 -> Int64 -> Int64
    forall a. Num a => a -> a -> a
    * Int64
    10Int64 -> Int -> Int64
    forall a b. (Num a, Integral b) => a -> b -> a
    ^Int
    n))
        where T Int
    n Int64
    t'  = (T -> Char -> T) -> T -> Text -> T
    forall a. (a -> Char -> a) -> a -> Text -> a
    T.foldl' T -> Char -> T
    step (Int -> Int64 -> T
    T Int
    12 (p -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral p
    a0)) Text
    t
              step :: T -> Char -> T
    step ma :: T
    ma@(T Int
    m Int64
    a) Char
    c
                  | Int
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    0    = T
    ma
                  | Bool
    otherwise = Int -> Int64 -> T
    T (Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1) (Int64
    10 Int64 -> Int64 -> Int64
    forall a. Num a => a -> a -> a
    * Int64
    a Int64 -> Int64 -> Int64
    forall a. Num a => a -> a -> a
    + Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Char -> Int
    ord Char
    c) Int64 -> Int64 -> Int64
    forall a. Bits a => a -> a -> a
    .&. Int64
    15)

    -- | 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 = do
      let maybeSkip :: Char -> Parser Text ()
    maybeSkip Char
    c = do Char
    ch <- Parser Text Char
    peekChar'; Bool -> Parser Text () -> Parser Text ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Char
    ch Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    c) (Parser Text Char -> Parser Text ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void Parser Text Char
    anyChar)
      Char -> Parser Text ()
    maybeSkip Char
    ' '
      Char
    ch <- (Char -> Bool) -> Parser Text Char
    satisfy ((Char -> Bool) -> Parser Text Char)
    -> (Char -> Bool) -> Parser Text Char
    forall a b. (a -> b) -> a -> b
    $ \Char
    c -> Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    'Z' Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '+' Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '-'
      if Char
    ch Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    'Z'
        then Maybe TimeZone -> Parser (Maybe TimeZone)
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe TimeZone
    forall a. Maybe a
    Nothing
        else do
          Int
    h <- Parser Int
    twoDigits
          Maybe Char
    mm <- Parser (Maybe Char)
    peekChar
          Int
    m <- case Maybe Char
    mm of
                 Just Char
    ':'           -> Parser Text Char
    anyChar Parser Text Char -> Parser Int -> Parser Int
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Parser Int
    twoDigits
                 Just Char
    d | Char -> Bool
    isDigit Char
    d -> Parser Int
    twoDigits
                 Maybe Char
    _                  -> Int -> Parser Int
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    0
          let off :: Int
    off | Char
    ch Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '-' = Int -> Int
    forall a. Num a => a -> a
    negate Int
    off0
                  | Bool
    otherwise = Int
    off0
              off0 :: Int
    off0 = Int
    h Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    60 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    m
          case Any
    forall a. HasCallStack => a
    undefined of
            Any
    _   | Int
    off Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 ->
                  Maybe TimeZone -> Parser (Maybe TimeZone)
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe TimeZone
    forall a. Maybe a
    Nothing
                | Int
    off Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < -Int
    720 Bool -> Bool -> Bool
    || Int
    off Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    840 Bool -> Bool -> Bool
    || Int
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    59 ->
                  String -> Parser (Maybe TimeZone)
    forall a. String -> Parser Text a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "invalid time zone offset"
                | Bool
    otherwise ->
                  let !tz :: TimeZone
    tz = Int -> TimeZone
    Local.minutesToTimeZone Int
    off
                  in Maybe TimeZone -> Parser (Maybe TimeZone)
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (TimeZone -> Maybe TimeZone
    forall a. a -> Maybe a
    Just TimeZone
    tz)

    -- | 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 = Day -> TimeOfDay -> LocalTime
    Local.LocalTime (Day -> TimeOfDay -> LocalTime)
    -> Parser Day -> Parser Text (TimeOfDay -> LocalTime)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser Day
    day Parser Text (TimeOfDay -> LocalTime)
    -> Parser Text Char -> Parser Text (TimeOfDay -> LocalTime)
    forall a b. Parser Text a -> Parser Text b -> Parser Text a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Parser Text Char
    daySep Parser Text (TimeOfDay -> LocalTime)
    -> Parser TimeOfDay -> Parser LocalTime
    forall a b. Parser Text (a -> b) -> Parser Text a -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Parser TimeOfDay
    timeOfDay
      where daySep :: Parser Text Char
    daySep = (Char -> Bool) -> Parser Text Char
    satisfy (\Char
    c -> Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    'T' Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    ' ')

    -- | Behaves as 'zonedTime', but converts any time zone offset into a
    -- UTC time.
    utcTime :: Parser UTCTime
    utcTime :: Parser UTCTime
    utcTime = do
      lt :: LocalTime
    lt@(Local.LocalTime Day
    d TimeOfDay
    t) <- Parser LocalTime
    localTime
      Maybe TimeZone
    mtz <- Parser (Maybe TimeZone)
    timeZone
      case Maybe TimeZone
    mtz of
        Maybe TimeZone
    Nothing -> let !tt :: DiffTime
    tt = TimeOfDay -> DiffTime
    Local.timeOfDayToTime TimeOfDay
    t
                   in UTCTime -> Parser UTCTime
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Day -> DiffTime -> UTCTime
    UTCTime Day
    d DiffTime
    tt)
        Just TimeZone
    tz -> UTCTime -> Parser UTCTime
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (UTCTime -> Parser UTCTime) -> UTCTime -> Parser UTCTime
    forall a b. (a -> b) -> a -> b
    $! TimeZone -> LocalTime -> UTCTime
    Local.localTimeToUTC TimeZone
    tz LocalTime
    lt

    -- | 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 = LocalTime -> TimeZone -> ZonedTime
    Local.ZonedTime (LocalTime -> TimeZone -> ZonedTime)
    -> Parser LocalTime -> Parser Text (TimeZone -> ZonedTime)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser LocalTime
    localTime Parser Text (TimeZone -> ZonedTime)
    -> Parser Text TimeZone -> Parser ZonedTime
    forall a b. Parser Text (a -> b) -> Parser Text a -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> (TimeZone -> Maybe TimeZone -> TimeZone
    forall a. a -> Maybe a -> a
    fromMaybe TimeZone
    utc (Maybe TimeZone -> TimeZone)
    -> Parser (Maybe TimeZone) -> Parser Text TimeZone
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser (Maybe TimeZone)
    timeZone)

    utc :: Local.TimeZone
    utc :: TimeZone
    utc = Int -> Bool -> String -> TimeZone
    Local.TimeZone Int
    0 Bool
    False String
    ""

    ------------------ Copy-pasted and adapted from base ------------------------

    txtToInteger :: T.Text -> Integer
    txtToInteger :: Text -> Integer
    txtToInteger Text
    bs
        | Int
    l Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    40    = Integer -> Int -> [Integer] -> Integer
    valInteger Integer
    10 Int
    l [ Int -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Char -> Int
    ord Char
    w Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    48) | Char
    w <- Text -> String
    T.unpack Text
    bs ]
        | Bool
    otherwise = Text -> Integer
    txtToIntegerSimple Text
    bs
      where
        l :: Int
    l = Text -> Int
    T.length Text
    bs

    txtToIntegerSimple :: T.Text -> Integer
    txtToIntegerSimple :: Text -> Integer
    txtToIntegerSimple = (Integer -> Char -> Integer) -> Integer -> Text -> Integer
    forall a. (a -> Char -> a) -> a -> Text -> a
    T.foldl' Integer -> Char -> Integer
    forall {a}. Num a => a -> Char -> a
    step Integer
    0 where
      step :: a -> Char -> a
    step a
    a Char
    b = a
    a a -> a -> a
    forall a. Num a => a -> a -> a
    * a
    10 a -> a -> a
    forall a. Num a => a -> a -> a
    + Int -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Char -> Int
    ord Char
    b Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    48) -- 48 = '0'

    -- A sub-quadratic algorithm for Integer. Pairs of adjacent radix b
    -- digits are combined into a single radix b^2 digit. This process is
    -- repeated until we are left with a single digit. This algorithm
    -- performs well only on large inputs, so we use the simple algorithm
    -- for smaller inputs.
    valInteger :: Integer -> Int -> [Integer] -> Integer
    valInteger :: Integer -> Int -> [Integer] -> Integer
    valInteger = Integer -> Int -> [Integer] -> Integer
    go
      where
        go :: Integer -> Int -> [Integer] -> Integer
        go :: Integer -> Int -> [Integer] -> Integer
    go Integer
    _ Int
    _ []  = Integer
    0
        go Integer
    _ Int
    _ [Integer
    d] = Integer
    d
        go Integer
    b Int
    l [Integer]
    ds
            | Int
    l Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    40 = Integer
    b' Integer -> Integer -> Integer
    forall a b. a -> b -> b
    `seq` Integer -> Int -> [Integer] -> Integer
    go Integer
    b' Int
    l' (Integer -> [Integer] -> [Integer]
    forall {t}. Num t => t -> [t] -> [t]
    combine Integer
    b [Integer]
    ds')
            | Bool
    otherwise = Integer -> [Integer] -> Integer
    valSimple Integer
    b [Integer]
    ds
          where
            -- ensure that we have an even number of digits
            -- before we call combine:
            ds' :: [Integer]
    ds' = if Int -> Bool
    forall a. Integral a => a -> Bool
    even Int
    l then [Integer]
    ds else Integer
    0 Integer -> [Integer] -> [Integer]
    forall a. a -> [a] -> [a]
    : [Integer]
    ds
            b' :: Integer
    b' = Integer
    b Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    b
            l' :: Int
    l' = (Int
    l Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `quot` Int
    2

        combine :: t -> [t] -> [t]
    combine t
    b (t
    d1 : t
    d2 : [t]
    ds) = t
    d t -> [t] -> [t]
    forall a b. a -> b -> b
    `seq` (t
    d t -> [t] -> [t]
    forall a. a -> [a] -> [a]
    : t -> [t] -> [t]
    combine t
    b [t]
    ds)
          where
            d :: t
    d = t
    d1 t -> t -> t
    forall a. Num a => a -> a -> a
    * t
    b t -> t -> t
    forall a. Num a => a -> a -> a
    + t
    d2
        combine t
    _ []  = []
        combine t
    _ [t
    _] = String -> [t]
    forall a. String -> a
    errorWithoutStackTrace String
    "this should not happen"

    -- The following algorithm is only linear for types whose Num operations
    -- are in constant time.
    valSimple :: Integer -> [Integer] -> Integer
    valSimple :: Integer -> [Integer] -> Integer
    valSimple Integer
    base = Integer -> [Integer] -> Integer
    forall {a}. Integral a => Integer -> [a] -> Integer
    go Integer
    0
      where
        go :: Integer -> [a] -> Integer
    go Integer
    r [] = Integer
    r
        go Integer
    r (a
    d : [a]
    ds) = Integer
    r' Integer -> Integer -> Integer
    forall a b. a -> b -> b
    `seq` Integer -> [a] -> Integer
    go Integer
    r' [a]
    ds
          where
            r' :: Integer
    r' = Integer
    r Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    base Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + a -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral a
    d