Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package ghc-attoparsec-iso8601 for
openSUSE:Factory checked in at 2022-02-11 23:07:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-attoparsec-iso8601 (Old)
and /work/SRC/openSUSE:Factory/.ghc-attoparsec-iso8601.new.1956 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-attoparsec-iso8601"
Fri Feb 11 23:07:48 2022 rev:15 rq:953386 version:1.0.2.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/ghc-attoparsec-iso8601/ghc-attoparsec-iso8601.changes
2021-12-19 17:34:58.340287585 +0100
+++
/work/SRC/openSUSE:Factory/.ghc-attoparsec-iso8601.new.1956/ghc-attoparsec-iso8601.changes
2022-02-11 23:09:33.234971030 +0100
@@ -1,0 +2,6 @@
+Sat Jan 1 19:05:59 UTC 2022 - Peter Simons <[email protected]>
+
+- Update attoparsec-iso8601 to version 1.0.2.1.
+ Upstream does not provide a change log file.
+
+-------------------------------------------------------------------
Old:
----
attoparsec-iso8601-1.0.2.0.tar.gz
attoparsec-iso8601.cabal
New:
----
attoparsec-iso8601-1.0.2.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-attoparsec-iso8601.spec ++++++
--- /var/tmp/diff_new_pack.dl8hTi/_old 2022-02-11 23:09:33.714972419 +0100
+++ /var/tmp/diff_new_pack.dl8hTi/_new 2022-02-11 23:09:33.718972430 +0100
@@ -1,7 +1,7 @@
#
# spec file for package ghc-attoparsec-iso8601
#
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,13 +18,12 @@
%global pkg_name attoparsec-iso8601
Name: ghc-%{pkg_name}
-Version: 1.0.2.0
+Version: 1.0.2.1
Release: 0
Summary: Parsing of ISO 8601 dates, originally from aeson
License: BSD-3-Clause
URL: https://hackage.haskell.org/package/%{pkg_name}
Source0:
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
-Source1:
https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/3.cabal#/%{pkg_name}.cabal
BuildRequires: ghc-Cabal-devel
BuildRequires: ghc-attoparsec-devel
BuildRequires: ghc-base-compat-batteries-devel
@@ -50,7 +49,6 @@
%prep
%autosetup -n %{pkg_name}-%{version}
-cp -p %{SOURCE1} %{pkg_name}.cabal
%build
%ghc_lib_build
++++++ attoparsec-iso8601-1.0.2.0.tar.gz -> attoparsec-iso8601-1.0.2.1.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/attoparsec-iso8601-1.0.2.0/Data/Attoparsec/Time/Internal.hs
new/attoparsec-iso8601-1.0.2.1/Data/Attoparsec/Time/Internal.hs
--- old/attoparsec-iso8601-1.0.2.0/Data/Attoparsec/Time/Internal.hs
2001-09-09 03:46:40.000000000 +0200
+++ new/attoparsec-iso8601-1.0.2.1/Data/Attoparsec/Time/Internal.hs
1970-01-01 01:00:00.000000000 +0100
@@ -1,49 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
--- |
--- Module: Data.Aeson.Internal.Time
--- Copyright: (c) 2015-2016 Bryan O'Sullivan
--- License: BSD3
--- Maintainer: Bryan O'Sullivan <[email protected]>
--- Stability: experimental
--- Portability: portable
-
-module Data.Attoparsec.Time.Internal
- (
- TimeOfDay64(..)
- , fromPico
- , toPico
- , diffTimeOfDay64
- , toTimeOfDay64
- ) where
-
-import Prelude.Compat
-
-import Data.Fixed (Fixed(MkFixed), Pico)
-import Data.Int (Int64)
-import Data.Time (TimeOfDay(..))
-import Data.Time.Clock.Compat
-
-toPico :: Integer -> Pico
-toPico = MkFixed
-
-fromPico :: Pico -> Integer
-fromPico (MkFixed i) = i
-
--- | Like TimeOfDay, but using a fixed-width integer for seconds.
-data TimeOfDay64 = TOD {-# UNPACK #-} !Int
- {-# UNPACK #-} !Int
- {-# UNPACK #-} !Int64
-
-posixDayLength :: DiffTime
-posixDayLength = 86400
-
-diffTimeOfDay64 :: DiffTime -> TimeOfDay64
-diffTimeOfDay64 t
- | t >= posixDayLength = TOD 23 59 (60000000000000 + pico (t -
posixDayLength))
- | otherwise = TOD (fromIntegral h) (fromIntegral m) s
- where (h,mp) = pico t `quotRem` 3600000000000000
- (m,s) = mp `quotRem` 60000000000000
- pico = fromIntegral . diffTimeToPicoseconds
-
-toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
-toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/attoparsec-iso8601-1.0.2.0/Data/Attoparsec/Time.hs
new/attoparsec-iso8601-1.0.2.1/Data/Attoparsec/Time.hs
--- old/attoparsec-iso8601-1.0.2.0/Data/Attoparsec/Time.hs 2001-09-09
03:46:40.000000000 +0200
+++ new/attoparsec-iso8601-1.0.2.1/Data/Attoparsec/Time.hs 1970-01-01
01:00:00.000000000 +0100
@@ -1,174 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE ScopedTypeVariables #-}
--- |
--- Module: Data.Aeson.Parser.Time
--- Copyright: (c) 2015-2016 Bryan O'Sullivan
--- License: BSD3
--- Maintainer: Bryan O'Sullivan <[email protected]>
--- Stability: experimental
--- Portability: portable
---
--- Parsers for parsing dates and times.
-
-module Data.Attoparsec.Time
- (
- day
- , localTime
- , timeOfDay
- , timeZone
- , utcTime
- , zonedTime
- , month
- , quarter
- ) where
-
-import Prelude.Compat
-
-import Control.Applicative ((<|>))
-import Control.Monad (void, when)
-import Data.Attoparsec.Text as A
-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.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@.
-day :: Parser Day
-day = do
- absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
- y <- (decimal <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
- m <- (twoDigits <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
- d <- twoDigits <|> fail "date must be of form [+,-]YYYY-MM-DD"
- maybe (fail "invalid date") return (fromGregorianValid (absOrNeg y) m d)
-
--- | Parse a month of the form @[+,-]YYYY-MM@.
-month :: Parser Month
-month = do
- absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
- y <- (decimal <* char '-') <|> fail "month must be of form [+,-]YYYY-MM"
- m <- twoDigits <|> fail "month must be of form [+,-]YYYY-MM"
- maybe (fail "invalid month") return (fromYearMonthValid (absOrNeg y) m)
-
--- | Parse a quarter of the form @[+,-]YYYY-QN@.
-quarter :: Parser Quarter
-quarter = do
- absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
- y <- (decimal <* char '-') <|> fail "month must be of form [+,-]YYYY-MM"
- _ <- char 'q' <|> char 'Q'
- q <- parseQ
- return $! fromYearQuarter (absOrNeg y) q
- where
- parseQ = Q1 <$ char '1'
- <|> Q2 <$ char '2'
- <|> Q3 <$ char '3'
- <|> Q4 <$ char '4'
-
--- | Parse a two-digit integer (e.g. day of month, hour).
-twoDigits :: Parser Int
-twoDigits = do
- a <- digit
- b <- digit
- let c2d c = ord c .&. 15
- return $! c2d a * 10 + c2d b
-
--- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
-timeOfDay :: Parser Local.TimeOfDay
-timeOfDay = do
- h <- twoDigits
- m <- char ':' *> twoDigits
- s <- option 0 (char ':' *> seconds)
- if h < 24 && m < 60 && s < 61
- then return (Local.TimeOfDay h m s)
- else fail "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 = do
- real <- twoDigits
- mc <- peekChar
- case mc of
- Just '.' -> do
- t <- anyChar *> takeWhile1 isDigit
- return $! parsePicos real t
- _ -> return $! fromIntegral real
- where
- parsePicos a0 t = toPico (fromIntegral (t' * 10^n))
- where T n t' = T.foldl' step (T 12 (fromIntegral a0)) t
- step ma@(T m a) c
- | m <= 0 = ma
- | otherwise = T (m-1) (10 * a + fromIntegral (ord c) .&. 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 = do
- let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
- maybeSkip ' '
- ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
- if ch == 'Z'
- then return Nothing
- else do
- h <- twoDigits
- mm <- peekChar
- m <- case mm of
- Just ':' -> anyChar *> twoDigits
- Just d | isDigit d -> twoDigits
- _ -> return 0
- let off | ch == '-' = negate off0
- | otherwise = off0
- off0 = h * 60 + m
- case undefined of
- _ | off == 0 ->
- return Nothing
- | off < -720 || off > 840 || m > 59 ->
- fail "invalid time zone offset"
- | otherwise ->
- let !tz = Local.minutesToTimeZone off
- in return (Just 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 = Local.LocalTime <$> day <* daySep <*> timeOfDay
- where daySep = satisfy (\c -> c == 'T' || c == ' ')
-
--- | Behaves as 'zonedTime', but converts any time zone offset into a
--- UTC time.
-utcTime :: Parser UTCTime
-utcTime = do
- lt@(Local.LocalTime d t) <- localTime
- mtz <- timeZone
- case mtz of
- Nothing -> let !tt = Local.timeOfDayToTime t
- in return (UTCTime d tt)
- Just tz -> return $! Local.localTimeToUTC tz 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 = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
-
-utc :: Local.TimeZone
-utc = Local.TimeZone 0 False ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/attoparsec-iso8601-1.0.2.0/attoparsec-iso8601.cabal
new/attoparsec-iso8601-1.0.2.1/attoparsec-iso8601.cabal
--- old/attoparsec-iso8601-1.0.2.0/attoparsec-iso8601.cabal 2001-09-09
03:46:40.000000000 +0200
+++ new/attoparsec-iso8601-1.0.2.1/attoparsec-iso8601.cabal 2001-09-09
03:46:40.000000000 +0200
@@ -1,6 +1,6 @@
name: attoparsec-iso8601
-version: 1.0.2.0
-synopsis: Parsing of ISO 8601 dates, originally from aeson.
+version: 1.0.2.1
+synopsis: Parsing of ISO 8601 dates, originally from aeson
description: Parsing of ISO 8601 dates, originally from aeson.
license: BSD3
license-file: LICENSE
@@ -14,7 +14,7 @@
homepage: https://github.com/haskell/aeson
bug-reports: https://github.com/haskell/aeson/issues
build-type: Simple
-tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC
== 8.4.4, GHC == 8.6.5, GHC == 8.8.3, GHC == 8.10.1
+tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC
== 8.8.4, GHC == 8.10.4, GHC == 9.0.1
extra-source-files:
README.md
@@ -29,19 +29,19 @@
manual: True
library
- hs-source-dirs: .
+ hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall
exposed-modules:
Data.Attoparsec.Time.Internal
Data.Attoparsec.Time
build-depends:
- attoparsec >= 0.13.0.1 && < 0.14.0.0,
- base >= 4.7 && < 5,
- base-compat-batteries >= 0.10.0 && < 0.12,
+ attoparsec >= 0.14.2 && < 0.15,
+ base >= 4.9 && < 5,
+ base-compat-batteries >= 0.10.0 && < 0.13,
time-compat >= 1.9.4 && < 1.10,
- text >= 1.1.1.0 && < 1.3.0.0,
- time >= 1.1.1.4 && < 1.12
+ text >= 1.2.3.0 && < 1.3.0.0 || >= 2.0 && <2.1,
+ time >= 1.6.0.1 && < 1.13
if flag(fast)
ghc-options: -O0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/attoparsec-iso8601-1.0.2.0/src/Data/Attoparsec/Time/Internal.hs
new/attoparsec-iso8601-1.0.2.1/src/Data/Attoparsec/Time/Internal.hs
--- old/attoparsec-iso8601-1.0.2.0/src/Data/Attoparsec/Time/Internal.hs
1970-01-01 01:00:00.000000000 +0100
+++ new/attoparsec-iso8601-1.0.2.1/src/Data/Attoparsec/Time/Internal.hs
2001-09-09 03:46:40.000000000 +0200
@@ -0,0 +1,49 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+-- |
+-- Module: Data.Aeson.Internal.Time
+-- Copyright: (c) 2015-2016 Bryan O'Sullivan
+-- License: BSD3
+-- Maintainer: Bryan O'Sullivan <[email protected]>
+-- Stability: experimental
+-- Portability: portable
+
+module Data.Attoparsec.Time.Internal
+ (
+ TimeOfDay64(..)
+ , fromPico
+ , toPico
+ , diffTimeOfDay64
+ , toTimeOfDay64
+ ) where
+
+import Prelude.Compat
+
+import Data.Fixed (Fixed(MkFixed), Pico)
+import Data.Int (Int64)
+import Data.Time (TimeOfDay(..))
+import Data.Time.Clock.Compat (DiffTime, diffTimeToPicoseconds)
+
+toPico :: Integer -> Pico
+toPico = MkFixed
+
+fromPico :: Pico -> Integer
+fromPico (MkFixed i) = i
+
+-- | Like TimeOfDay, but using a fixed-width integer for seconds.
+data TimeOfDay64 = TOD {-# UNPACK #-} !Int
+ {-# UNPACK #-} !Int
+ {-# UNPACK #-} !Int64
+
+posixDayLength :: DiffTime
+posixDayLength = 86400
+
+diffTimeOfDay64 :: DiffTime -> TimeOfDay64
+diffTimeOfDay64 t
+ | t >= posixDayLength = TOD 23 59 (60000000000000 + pico (t -
posixDayLength))
+ | otherwise = TOD (fromIntegral h) (fromIntegral m) s
+ where (h,mp) = pico t `quotRem` 3600000000000000
+ (m,s) = mp `quotRem` 60000000000000
+ pico = fromIntegral . diffTimeToPicoseconds
+
+toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
+toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/attoparsec-iso8601-1.0.2.0/src/Data/Attoparsec/Time.hs
new/attoparsec-iso8601-1.0.2.1/src/Data/Attoparsec/Time.hs
--- old/attoparsec-iso8601-1.0.2.0/src/Data/Attoparsec/Time.hs 1970-01-01
01:00:00.000000000 +0100
+++ new/attoparsec-iso8601-1.0.2.1/src/Data/Attoparsec/Time.hs 2001-09-09
03:46:40.000000000 +0200
@@ -0,0 +1,174 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-- |
+-- Module: Data.Aeson.Parser.Time
+-- Copyright: (c) 2015-2016 Bryan O'Sullivan
+-- License: BSD3
+-- Maintainer: Bryan O'Sullivan <[email protected]>
+-- Stability: experimental
+-- Portability: portable
+--
+-- Parsers for parsing dates and times.
+
+module Data.Attoparsec.Time
+ (
+ day
+ , localTime
+ , timeOfDay
+ , timeZone
+ , utcTime
+ , zonedTime
+ , month
+ , quarter
+ ) where
+
+import Prelude.Compat
+
+import Control.Applicative ((<|>))
+import Control.Monad (void, when)
+import Data.Attoparsec.Text (Parser, char, decimal, 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.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@.
+day :: Parser Day
+day = do
+ absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
+ y <- (decimal <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
+ m <- (twoDigits <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
+ d <- twoDigits <|> fail "date must be of form [+,-]YYYY-MM-DD"
+ maybe (fail "invalid date") return (fromGregorianValid (absOrNeg y) m d)
+
+-- | Parse a month of the form @[+,-]YYYY-MM@.
+month :: Parser Month
+month = do
+ absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
+ y <- (decimal <* char '-') <|> fail "month must be of form [+,-]YYYY-MM"
+ m <- twoDigits <|> fail "month must be of form [+,-]YYYY-MM"
+ maybe (fail "invalid month") return (fromYearMonthValid (absOrNeg y) m)
+
+-- | Parse a quarter of the form @[+,-]YYYY-QN@.
+quarter :: Parser Quarter
+quarter = do
+ absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
+ y <- (decimal <* char '-') <|> fail "month must be of form [+,-]YYYY-MM"
+ _ <- char 'q' <|> char 'Q'
+ q <- parseQ
+ return $! fromYearQuarter (absOrNeg y) q
+ where
+ parseQ = Q1 <$ char '1'
+ <|> Q2 <$ char '2'
+ <|> Q3 <$ char '3'
+ <|> Q4 <$ char '4'
+
+-- | Parse a two-digit integer (e.g. day of month, hour).
+twoDigits :: Parser Int
+twoDigits = do
+ a <- digit
+ b <- digit
+ let c2d c = ord c .&. 15
+ return $! c2d a * 10 + c2d b
+
+-- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
+timeOfDay :: Parser Local.TimeOfDay
+timeOfDay = do
+ h <- twoDigits
+ m <- char ':' *> twoDigits
+ s <- option 0 (char ':' *> seconds)
+ if h < 24 && m < 60 && s < 61
+ then return (Local.TimeOfDay h m s)
+ else fail "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 = do
+ real <- twoDigits
+ mc <- peekChar
+ case mc of
+ Just '.' -> do
+ t <- anyChar *> takeWhile1 isDigit
+ return $! parsePicos real t
+ _ -> return $! fromIntegral real
+ where
+ parsePicos a0 t = toPico (fromIntegral (t' * 10^n))
+ where T n t' = T.foldl' step (T 12 (fromIntegral a0)) t
+ step ma@(T m a) c
+ | m <= 0 = ma
+ | otherwise = T (m-1) (10 * a + fromIntegral (ord c) .&. 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 = do
+ let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
+ maybeSkip ' '
+ ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
+ if ch == 'Z'
+ then return Nothing
+ else do
+ h <- twoDigits
+ mm <- peekChar
+ m <- case mm of
+ Just ':' -> anyChar *> twoDigits
+ Just d | isDigit d -> twoDigits
+ _ -> return 0
+ let off | ch == '-' = negate off0
+ | otherwise = off0
+ off0 = h * 60 + m
+ case undefined of
+ _ | off == 0 ->
+ return Nothing
+ | off < -720 || off > 840 || m > 59 ->
+ fail "invalid time zone offset"
+ | otherwise ->
+ let !tz = Local.minutesToTimeZone off
+ in return (Just 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 = Local.LocalTime <$> day <* daySep <*> timeOfDay
+ where daySep = satisfy (\c -> c == 'T' || c == ' ')
+
+-- | Behaves as 'zonedTime', but converts any time zone offset into a
+-- UTC time.
+utcTime :: Parser UTCTime
+utcTime = do
+ lt@(Local.LocalTime d t) <- localTime
+ mtz <- timeZone
+ case mtz of
+ Nothing -> let !tt = Local.timeOfDayToTime t
+ in return (UTCTime d tt)
+ Just tz -> return $! Local.localTimeToUTC tz 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 = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
+
+utc :: Local.TimeZone
+utc = Local.TimeZone 0 False ""