utc 0.1.0.1 → 0.2.0.0
raw patch · 20 files changed
+506/−255 lines, 20 filesdep +exceptions
Dependencies added: exceptions
Files
- Data/UTC.hs +21/−12
- Data/UTC/Class.hs +0/−2
- Data/UTC/Class/HasUnixTime.hs +4/−1
- Data/UTC/Class/IsDate.hs +8/−6
- Data/UTC/Class/IsTime.hs +10/−8
- Data/UTC/Class/IsUnixTime.hs +3/−1
- Data/UTC/Class/Midnight.hs +0/−9
- Data/UTC/Format/Iso8601.hs +198/−0
- Data/UTC/Format/Rfc3339.hs +16/−6
- Data/UTC/Format/Rfc3339/Builder.hs +1/−1
- Data/UTC/Format/Rfc3339/Parser.hs +12/−10
- Data/UTC/Internal.hs +30/−0
- Data/UTC/Type.hs +3/−0
- Data/UTC/Type/Date.hs +25/−4
- Data/UTC/Type/DateTime.hs +71/−97
- Data/UTC/Type/Exception.hs +18/−0
- Data/UTC/Type/Local.hs +46/−70
- Data/UTC/Type/Time.hs +26/−10
- tests/Test.hs +4/−6
- utc.cabal +10/−12
Data/UTC.hs view
@@ -6,8 +6,8 @@ -- ** General Concepts - -- *** Handling Failure- -- $failure+ -- *** Handling Exceptions+ -- $exceptions -- *** Integer vs. Int -- $integerint@@ -22,9 +22,8 @@ , IsTime (..) -- ** Unix Time , IsUnixTime(..)- -- ** Epoch / Midnight+ -- ** Epoch , Epoch(..)- , Midnight(..) -- ** Getting (Current) Timestamps , HasUnixTime (..) -- * Generic Date/Time Types@@ -36,6 +35,8 @@ , DateTime (..) -- ** Local Time , Local (..)+ -- ** Exception+ , UtcException (..) -- * Formatting -- ** RFC 3339@@ -43,10 +44,12 @@ , Rfc3339Parser(..) -- *** Rendering , Rfc3339Renderer(..)+ -- ** ISO 8601+ -- *** Rendering+ , Iso8601Renderer(..) ) where import Data.UTC.Class.Epoch-import Data.UTC.Class.Midnight import Data.UTC.Class.IsDate import Data.UTC.Class.IsTime import Data.UTC.Class.IsUnixTime@@ -55,7 +58,9 @@ import Data.UTC.Type.Time import Data.UTC.Type.DateTime import Data.UTC.Type.Local+import Data.UTC.Type.Exception import Data.UTC.Format.Rfc3339+import Data.UTC.Format.Iso8601 -- $quickstart --@@ -63,13 +68,13 @@ -- It supports all functions you'll find below. -- Use 'Maybe' for all occurences of 'm'. ----- > Prelude> :m +Data.UTC+-- > Prelude> import Data.UTC -- > Prelude Data.UTC> type MT = Maybe (Local DateTime) -- > Prelude Data.UTC> type MS = Maybe String -- > Prelude Data.UTC> (parseRfc3339 "2014-12-24T13:37:00Z" :: MT) >>= addHours 25 >>= setMonth 1 >>= renderRfc3339 :: MS -- > Just "2014-01-25T14:37:00Z" --- $failure+-- $exceptions -- -- The library's main idea is to make it hard to use it wrong. It should -- be impossible by the API's design to construct invalid date or time values.@@ -79,16 +84,20 @@ -- functions throw exceptions via 'Prelude.error' or 'Prelude.undefined'. -- -- Whenever a function cannot be total, its result is wrapped in a type variable with--- a 'Prelude.Monad' restriction on it. You can always just use 'Prelude.Maybe' and+-- a 'Monad.Control.MonadThrow' restriction on it which works nicely even in complex+-- monad transformer stacks. You can always just use 'Prelude.Maybe' and -- 'Data.Maybe.fromMaybe' to obtain a plain value: ----- > fromMaybe epoch (addDays 24 epoch) :: Date+-- > fromMaybe epoch (addDays 24 epoch) :: Date -- > > 1970-01-25 ----- Using another 'Prelude.Monad' instance might give you additional information in case of failure:+-- Using another 'Monad.Control.MonadThrow' instance might give you additional information in case of failure: ----- > setHour 10 midnight >>= setMinute 61 :: IO Time--- > > *** Exception: user error (Time.setMinute 61)+-- > setHour 10 epoch >>= setMinute 61 :: IO Time+-- > > *** Exception: UtcException "Time: setMinute 61 10:00:00"+-- >+-- > setHour 10 epoch >>= setMinute 61 :: Either Control.Exception.SomeException Time+-- > > Left (UtcException "Time: setMinute 61 10:00:00") -- $integerint --
Data/UTC/Class.hs view
@@ -4,11 +4,9 @@ , module Data.UTC.Class.IsUnixTime , module Data.UTC.Class.HasUnixTime , module Data.UTC.Class.Epoch- , module Data.UTC.Class.Midnight ) where import Data.UTC.Class.Epoch-import Data.UTC.Class.Midnight import Data.UTC.Class.IsDate import Data.UTC.Class.IsTime import Data.UTC.Class.IsUnixTime
Data/UTC/Class/HasUnixTime.hs view
@@ -1,10 +1,13 @@ {-# LANGUAGE Safe #-} module Data.UTC.Class.HasUnixTime where +import Control.Monad.Catch+ import Data.Ratio import System.Clock as C import Data.UTC.Class.IsUnixTime+import Data.UTC.Type.Exception -- | This class defines an interface for contexts that can be asked for a timestamp. --@@ -40,5 +43,5 @@ = do TimeSpec s ns <- C.getTime Realtime case fromUnixSeconds ((fromIntegral s) % 1 + (fromIntegral ns) % 1000000000) of Just t -> return t- Nothing -> fail "Data.UTC.Class.HasUnixTime.getUnixTime: failed"+ Nothing -> throwM $ UtcException "HasUnixTime IO: getUnixTime"
Data/UTC/Class/IsDate.hs view
@@ -3,6 +3,8 @@ ( IsDate (..) ) where +import Control.Monad.Catch+ import Data.UTC.Internal import Data.UTC.Class.Epoch @@ -34,15 +36,15 @@ -- > > Just 2005-02-28 -- > setYear 2005 "2004-02-29" :: Maybe Date -- > > Nothing- setYear :: (Monad m) => Integer -> t -> m t+ setYear :: (MonadThrow m) => Integer -> t -> m t -- | Sets the month of year and fails if the result would be invalid. -- -- The function only accepts input ranging from 1 to 12.- setMonth :: (Monad m) => Integer -> t -> m t+ setMonth :: (MonadThrow m) => Integer -> t -> m t -- | Sets the day of month and fails if the result would be invalid. -- -- The function only accepts input ranging from 1 to 31 (or less depending on month and year).- setDay :: (Monad m) => Integer -> t -> m t+ setDay :: (MonadThrow m) => Integer -> t -> m t -- | A /year/ is a relative amount of time. -- The function's semantic is a follows:@@ -57,7 +59,7 @@ -- > > Just 2004-02-29 -- > addYears 1 "2000-02-29" :: Maybe Date -- > > Just 2001-02-28- addYears :: (Monad m) => Integer -> t -> m t+ addYears :: (MonadThrow m) => Integer -> t -> m t addYears ys t = if isValidDate (year t + ys, month t, day t) then setYear (year t + ys) t@@ -72,7 +74,7 @@ -- -- > addMonths (-13) "1970-01-01" :: Maybe Date -- > > Just 1968-12-01- addMonths :: (Monad m) => Integer -> t -> m t+ addMonths :: (MonadThrow m) => Integer -> t -> m t addMonths ms t = setDay 1 t >>= setYear y >>= setMonth m >>= setDay d where@@ -97,7 +99,7 @@ -- > > Just 1971-01-01 -- > addDays 365 "2000-01-01" :: Maybe Date -- > > Just 2000-12-31- addDays :: (Monad m) => Integer -> t -> m t+ addDays :: (MonadThrow m) => Integer -> t -> m t addDays ds t -- setDay 1 to avoid intermediate generation of invalid dates! = setDay 1 t >>= setYear y >>= setMonth m >>= setDay d
Data/UTC/Class/IsTime.hs view
@@ -3,6 +3,8 @@ ( IsTime (..) ) where +import Control.Monad.Catch+ import Data.Ratio import Data.UTC.Internal@@ -21,26 +23,26 @@ -- | Accepts values in the range 0 to 23. -- -- The function fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- setHour :: (Monad m) => Integer -> t -> m t+ setHour :: (MonadThrow m) => Integer -> t -> m t -- | Accepts values in the range 0 to 59. -- -- The function fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- setMinute :: (Monad m) => Integer -> t -> m t+ setMinute :: (MonadThrow m) => Integer -> t -> m t -- | Accepts values in the range 0 to 59. -- -- The function fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- setSecond :: (Monad m) => Integer -> t -> m t+ setSecond :: (MonadThrow m) => Integer -> t -> m t -- | Accepts values in the range 0.0 <= x < 1.0. -- -- The function fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- setSecondFraction :: (Monad m) => Rational -> t -> m t+ setSecondFraction :: (MonadThrow m) => Rational -> t -> m t -- | Adds an arbitrary count of hours (positive or negative). -- -- * Full days flow over to 'Data.UTC.addDays' if the type is also an instance of 'Data.UTC.Class.IsDate' (this is the case for 'Data.UTC.DateTime'). -- * Types not implementing the 'Data.UTC.Class.IsDate' class should just ignore the days part on overflow (like 'Data.UTC.Time' does). -- * Fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- addHours :: (Monad m) => Integer -> t -> m t+ addHours :: (MonadThrow m) => Integer -> t -> m t addHours h t = setHour hors t where@@ -51,7 +53,7 @@ -- -- * Full hours flow over to 'addHours'. -- * Fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- addMinutes :: (Monad m) => Integer -> t -> m t+ addMinutes :: (MonadThrow m) => Integer -> t -> m t addMinutes m t = setMinute mins t >>= addHours hors where@@ -63,7 +65,7 @@ -- -- * Full minutes flow over to 'addMinutes'. -- * Fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- addSeconds :: (Monad m) => Integer -> t -> m t+ addSeconds :: (MonadThrow m) => Integer -> t -> m t addSeconds s t = setSecond secs t >>= addMinutes mins where@@ -76,7 +78,7 @@ -- * Full seconds flow over to 'addSeconds'. -- * Instances of this class are not required to preserve full precision (although 'Data.UTC.Time' and 'Data.UTC.DateTime' do so). -- * Fails if the result cannot be represented by the type (cannot happen for 'Data.UTC.Time' and 'Data.UTC.DateTime').- addSecondFractions :: (Monad m) => Rational -> t -> m t+ addSecondFractions :: (MonadThrow m) => Rational -> t -> m t addSecondFractions f t | f == 0 = return t | f >= 0 = setSecondFraction frcs t >>= addSeconds secs
Data/UTC/Class/IsUnixTime.hs view
@@ -3,6 +3,8 @@ ( IsUnixTime(..) ) where +import Control.Monad.Catch+ -- | This class is for types that have a well-defined -- mapping to and from the <https://en.wikipedia.org/wiki/Unix_time Unix Time> system -- (based on <https://en.wikipedia.org/wiki/Coordinated_Universal_Time UTC>).@@ -18,4 +20,4 @@ -- The concrete behaviour of your system clock is implementation dependant. class IsUnixTime t where unixSeconds :: t -> Rational- fromUnixSeconds :: Monad m => Rational -> m t+ fromUnixSeconds :: MonadThrow m => Rational -> m t
− Data/UTC/Class/Midnight.hs
@@ -1,9 +0,0 @@-{-# LANGUAGE Safe #-}-module Data.UTC.Class.Midnight- ( Midnight(..)- ) where---- | The beginning of a day: 00:00:00-class Midnight t where- midnight :: t-
+ Data/UTC/Format/Iso8601.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE FlexibleInstances #-}+module Data.UTC.Format.Iso8601 where++import Control.Monad.Catch++import Data.Monoid+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BS+import qualified Data.ByteString.Lazy as BSL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL++import Data.UTC.Class.IsDate+import Data.UTC.Class.IsTime+import Data.UTC.Type.Exception++class Iso8601Renderer string where+ -- | __YYYYMMDD__+ renderIso8601CalendarDate :: (MonadThrow m, IsDate t) => t -> m string+ -- | __YYYY-MM-DD__ (extended format)+ renderIso8601CalendarDate' :: (MonadThrow m, IsDate t) => t -> m string++ -- | __hhmmss__+ renderIso8601TimeHms :: (MonadThrow m, IsTime t) => t -> m string+ -- | __hh:mm:ss__ (extended format)+ renderIso8601TimeHms' :: (MonadThrow m, IsTime t) => t -> m string+ -- | __hhmm__+ renderIso8601TimeHm :: (MonadThrow m, IsTime t) => t -> m string+ -- | __hh:mm__ (extended format)+ renderIso8601TimeHm' :: (MonadThrow m, IsTime t) => t -> m string++instance Iso8601Renderer BS.ByteString where+ renderIso8601CalendarDate t+ = renderIso8601CalendarDate t >>= return . BSL.toStrict+ renderIso8601CalendarDate' t+ = renderIso8601CalendarDate' t >>= return . BSL.toStrict+ renderIso8601TimeHms t+ = renderIso8601TimeHms t >>= return . BSL.toStrict+ renderIso8601TimeHms' t+ = renderIso8601TimeHms' t >>= return . BSL.toStrict+ renderIso8601TimeHm t+ = renderIso8601TimeHm t >>= return . BSL.toStrict+ renderIso8601TimeHm' t+ = renderIso8601TimeHm' t >>= return . BSL.toStrict++instance Iso8601Renderer T.Text where+ renderIso8601CalendarDate t+ = renderIso8601CalendarDate t >>= return . T.decodeUtf8+ renderIso8601CalendarDate' t+ = renderIso8601CalendarDate' t >>= return . T.decodeUtf8+ renderIso8601TimeHms t+ = renderIso8601TimeHms t >>= return . T.decodeUtf8+ renderIso8601TimeHms' t+ = renderIso8601TimeHms' t >>= return . T.decodeUtf8+ renderIso8601TimeHm t+ = renderIso8601TimeHm t >>= return . T.decodeUtf8+ renderIso8601TimeHm' t+ = renderIso8601TimeHm' t >>= return . T.decodeUtf8++instance Iso8601Renderer TL.Text where+ renderIso8601CalendarDate t+ = renderIso8601CalendarDate t >>= return . TL.decodeUtf8+ renderIso8601CalendarDate' t+ = renderIso8601CalendarDate' t >>= return . TL.decodeUtf8+ renderIso8601TimeHms t+ = renderIso8601TimeHms t >>= return . TL.decodeUtf8+ renderIso8601TimeHms' t+ = renderIso8601TimeHms' t >>= return . TL.decodeUtf8+ renderIso8601TimeHm t+ = renderIso8601TimeHm t >>= return . TL.decodeUtf8+ renderIso8601TimeHm' t+ = renderIso8601TimeHm' t >>= return . TL.decodeUtf8++instance Iso8601Renderer [Char] where+ renderIso8601CalendarDate t + = renderIso8601CalendarDate t >>= return . T.unpack+ renderIso8601CalendarDate' t + = renderIso8601CalendarDate' t >>= return . T.unpack+ renderIso8601TimeHms t+ = renderIso8601TimeHms t >>= return . T.unpack+ renderIso8601TimeHms' t+ = renderIso8601TimeHms' t >>= return . T.unpack+ renderIso8601TimeHm t+ = renderIso8601TimeHm t >>= return . T.unpack+ renderIso8601TimeHm' t+ = renderIso8601TimeHm' t >>= return . T.unpack++instance Iso8601Renderer BSL.ByteString where+ renderIso8601CalendarDate t+ | 0 <= yyyy && yyyy <= 9999+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word16HexFixed (y3*16*16*16 + y2*16*16 + y1*16 + y0)+ , BS.word8HexFixed (m1*16 + m0)+ , BS.word8HexFixed (d1*16 + d0)+ ]+ | otherwise+ = throwM $ UtcException $ "Iso8601: renderIso8601CalendarDate (year " ++ show yyyy ++ " out of range 0-9999)"+ where+ yyyy = year t+ mm = month t+ dd = day t+ y3 = fromIntegral $ yyyy `div` 1000 `mod` 10+ y2 = fromIntegral $ yyyy `div` 100 `mod` 10+ y1 = fromIntegral $ yyyy `div` 10 `mod` 10+ y0 = fromIntegral $ yyyy `div` 1 `mod` 10+ m1 = fromIntegral $ mm `div` 10 `mod` 10+ m0 = fromIntegral $ mm `div` 1 `mod` 10+ d1 = fromIntegral $ dd `div` 10 `mod` 10+ d0 = fromIntegral $ dd `div` 1 `mod` 10++ renderIso8601CalendarDate' t+ | 0 <= yyyy && yyyy <= 9999+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word16HexFixed (y3*16*16*16 + y2*16*16 + y1*16 + y0)+ , BS.char7 '-'+ , BS.word8HexFixed (m1*16 + m0)+ , BS.char7 '-'+ , BS.word8HexFixed (d1*16 + d0)+ ]+ | otherwise+ = throwM $ UtcException $ "Iso8601: renderIso8601CalendarDate (year " ++ show yyyy ++ " out of range 0-9999)"+ where+ yyyy = year t+ mm = month t+ dd = day t+ y3 = fromIntegral $ yyyy `div` 1000 `mod` 10+ y2 = fromIntegral $ yyyy `div` 100 `mod` 10+ y1 = fromIntegral $ yyyy `div` 10 `mod` 10+ y0 = fromIntegral $ yyyy `div` 1 `mod` 10+ m1 = fromIntegral $ mm `div` 10 `mod` 10+ m0 = fromIntegral $ mm `div` 1 `mod` 10+ d1 = fromIntegral $ dd `div` 10 `mod` 10+ d0 = fromIntegral $ dd `div` 1 `mod` 10++ renderIso8601TimeHms t+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word8HexFixed (h1*16 + h0)+ , BS.word8HexFixed (m1*16 + m0)+ , BS.word8HexFixed (s1*16 + s0)+ ]+ where+ (h1,h0,m1,m0,s1,s0) = timeDigits t++ renderIso8601TimeHms' t+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word8HexFixed (h1*16 + h0)+ , BS.char7 '-'+ , BS.word8HexFixed (m1*16 + m0)+ , BS.char7 '-'+ , BS.word8HexFixed (s1*16 + s0)+ ]+ where+ (h1,h0,m1,m0,s1,s0) = timeDigits t++ renderIso8601TimeHm t+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word8HexFixed (h1*16 + h0)+ , BS.word8HexFixed (m1*16 + m0)+ ]+ where+ (h1,h0,m1,m0,_,_) = timeDigits t++ renderIso8601TimeHm' t+ = return+ $ BS.toLazyByteString+ $ mconcat+ [ BS.word8HexFixed (h1*16 + h0)+ , BS.char7 '-'+ , BS.word8HexFixed (m1*16 + m0)+ ]+ where+ (h1,h0,m1,m0,_,_) = timeDigits t++timeDigits t+ = (h1,h0,m1,m0,s1,s0)+ where+ hh = hour t+ mm = minute t+ ss = second t+ h1 = fromIntegral $ hh `div` 10 `mod` 10+ h0 = fromIntegral $ hh `div` 1 `mod` 10+ m1 = fromIntegral $ mm `div` 10 `mod` 10+ m0 = fromIntegral $ mm `div` 1 `mod` 10+ s1 = fromIntegral $ ss `div` 10 `mod` 10+ s0 = fromIntegral $ ss `div` 1 `mod` 10+
Data/UTC/Format/Rfc3339.hs view
@@ -8,6 +8,8 @@ , rfc3339Parser, rfc3339Builder ) where +import Control.Monad.Catch+ import qualified Data.Attoparsec.ByteString as Atto import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL@@ -21,17 +23,18 @@ import Data.UTC.Class.IsDate import Data.UTC.Class.IsTime import Data.UTC.Type.Local+import Data.UTC.Type.Exception import Data.UTC.Format.Rfc3339.Parser import Data.UTC.Format.Rfc3339.Builder class Rfc3339Parser a where- parseRfc3339 :: (Monad m, IsDate t, IsTime t, Epoch t) => a -> m (Local t)+ parseRfc3339 :: (MonadThrow m, IsDate t, IsTime t, Epoch t) => a -> m (Local t) instance Rfc3339Parser BS.ByteString where parseRfc3339 s = case Atto.parseOnly rfc3339Parser s of- Right t -> return t- Left _ -> fail ""+ Right t -> t+ Left _ -> throwM $ UtcException $ "Rfc3339Parser: parseRfc3339 " ++ show s instance Rfc3339Parser BSL.ByteString where parseRfc3339 s@@ -49,9 +52,16 @@ parseRfc3339 s = parseRfc3339 (T.pack s) --class Rfc3339Renderer a where- renderRfc3339 :: (Monad m, IsDate t, IsTime t, Epoch t) => Local t -> m a+-- | > setYear 1987 (epoch :: DateTime) +-- > >>= setMonth 7 +-- > >>= setDay 10 +-- > >>= setHour 12 +-- > >>= setMinute 4 +-- > >>= return . (flip Local) (Just 0) +-- > >>= renderRfc3339 :: Maybe String+-- > > Just "1987-07-10T12:04:00Z"+class Rfc3339Renderer string where+ renderRfc3339 :: (MonadThrow m, IsDate t, IsTime t, Epoch t) => Local t -> m string instance Rfc3339Renderer BS.ByteString where renderRfc3339 t
Data/UTC/Format/Rfc3339/Builder.hs view
@@ -11,7 +11,7 @@ import Data.UTC.Class.IsTime rfc3339Builder :: (Monad m, IsDate t, IsTime t) => Local t -> m BS.Builder-rfc3339Builder (Local t os)+rfc3339Builder (Local os t) = do -- calculate the single digits let y3 = fromIntegral $ year t `div` 1000 `mod` 10 y2 = fromIntegral $ year t `div` 100 `mod` 10
Data/UTC/Format/Rfc3339/Parser.hs view
@@ -2,6 +2,8 @@ ( rfc3339Parser ) where +import Control.Monad.Catch+ import Data.Ratio import Data.Attoparsec.ByteString ( Parser, skipWhile, choice, option, satisfy )@@ -12,7 +14,7 @@ import Data.UTC.Class.IsTime import Data.UTC.Type.Local -rfc3339Parser :: (IsDate t, IsTime t) => Parser (Local t)+rfc3339Parser :: (MonadThrow m, IsDate t, IsTime t) => Parser (m (Local t)) rfc3339Parser = do year' <- dateFullYear _ <- char '-'@@ -27,15 +29,15 @@ second' <- timeSecond secfrac' <- option 0 timeSecfrac offset' <- timeOffset- datetime <- return epoch- >>= setYear year'- >>= setMonth month'- >>= setDay day'- >>= setHour hour'- >>= setMinute minute'- >>= setSecond second'- >>= setSecondFraction secfrac'- return (Local datetime offset')++ return $ do datetime <- setYear year' epoch+ >>= setMonth month'+ >>= setDay day'+ >>= setHour hour'+ >>= setMinute minute'+ >>= setSecond second'+ >>= setSecondFraction secfrac'+ return (Local offset' datetime) where dateFullYear = decimal4
Data/UTC/Internal.hs view
@@ -11,8 +11,13 @@ , secsPerDay, secsPerHour, secsPerMinute, minsPerHour, hoursPerDay , monthsPerYear++ , fixedDecimal+ , decimalFraction ) where +import Data.Ratio+ deltaUnixEpochCommonEpoch :: Rational deltaUnixEpochCommonEpoch = 62167219200@@ -160,3 +165,28 @@ | otherwise = False isLeapYear = (y `mod` 4 == 0) && ((y `mod` 400 == 0) || (y `mod` 100 /= 0))++fixedDecimal :: Integer -> Integer -> String+fixedDecimal digits i+ = f digits i []+ where+ f n i accum | n <= 0 = accum+ | otherwise = f (n - 1) (i `div` 10)+ ((toEnum $ fromIntegral $ 48 + i `mod` 10):accum)++decimalFraction :: Integer -> Rational -> String+decimalFraction _ 0+ = ""+decimalFraction limit r+ = '.':(df limit r)+ where+ df limit 0+ = ""+ df 0 _+ = "..."+ df limit r+ = ch:(df (limit - 1) r')+ where+ r10 = r * 10+ ch = toEnum $ fromIntegral $ 48 + (truncate $ r10) `mod` 10+ r' = r10 - (truncate r10 % 1)
Data/UTC/Type.hs view
@@ -3,9 +3,12 @@ , module Data.UTC.Type.Time , module Data.UTC.Type.DateTime , module Data.UTC.Type.Local+ , module Data.UTC.Type.Exception ) where import Data.UTC.Type.Date import Data.UTC.Type.Time import Data.UTC.Type.DateTime import Data.UTC.Type.Local++import Data.UTC.Type.Exception
Data/UTC/Type/Date.hs view
@@ -2,12 +2,15 @@ ( Date () ) where +import Control.Monad.Catch+ import Data.Ratio import Data.UTC.Class.Epoch import Data.UTC.Class.IsDate import Data.UTC.Class.IsUnixTime import Data.UTC.Internal+import Data.UTC.Type.Exception -- | This type represents dates in the __Proleptic Gregorian Calendar__. --@@ -17,13 +20,31 @@ -- Use 'Data.UTC.epoch' or a parser to construct values. -- * The instance of 'Prelude.Show' is only meant for debugging purposes -- and is subject to change.+--+-- > > show (epoch :: Date)+-- > 1970-01-01 data Date = Date { dYear :: Integer , dMonth :: Integer , dDay :: Integer- } deriving (Eq, Ord, Show)+ } deriving (Eq, Ord) +instance Show Date where+ show (Date yy mm dd)+ = concat+ [ if yy < 0+ then "-"+ else ""+ , if abs yy > 9999+ then show (abs yy)+ else fixedDecimal 4 (abs yy)+ , "-"+ , fixedDecimal 2 mm+ , "-"+ , fixedDecimal 2 dd+ ]+ instance Epoch Date where epoch = Date@@ -59,13 +80,13 @@ setYear x t = if isValidDate (x, month t, day t) then return $ t { dYear = x }- else fail $ "Dated.setYear " ++ show x+ else throwM $ UtcException $ "IsDate Date: setYear " ++ show x ++ " " ++ show t setMonth x t = if isValidDate (year t, x, day t) then return $ t { dMonth = x }- else fail $ "Dated.setMonth " ++ show x+ else throwM $ UtcException $ "IsDate Date: setMonth " ++ show x ++ " " ++ show t setDay x t = if isValidDate (year t, month t, x) then return $ t { dDay = x }- else fail $ "Dated.setDay " ++ show x+ else throwM $ UtcException $ "IsDate Date: setDay " ++ show x ++ " " ++ show t
Data/UTC/Type/DateTime.hs view
@@ -4,7 +4,6 @@ DateTime (..) ) where -import Data.String import Data.Maybe import Data.UTC.Class.Epoch@@ -14,7 +13,6 @@ import Data.UTC.Type.Date import Data.UTC.Type.Time import Data.UTC.Type.Local-import Data.UTC.Format.Rfc3339 import Data.UTC.Internal -- | A time representation based on a 'Data.UTC.Date' and the 'Data.UTC.Time' of the day.@@ -22,9 +20,11 @@ -- * The type uses multiprecision integers internally and is able to represent -- any UTC date in the past and in the future with arbitrary precision -- (apart from the time span within a leap second).--- * The instances of 'Data.String.IsString' and 'Prelude.Show' are only--- meant for debugging purposes and default to 'epoch' in case of--- failure. Don't rely on their behaviour!+-- * The instance of 'Prelude.Show' is only+-- meant for debugging purposes. Don't rely on its behaviour!+--+-- > > show (epoch :: DateTime)+-- > 1970-01-01T00:00:00 data DateTime = DateTime { date :: Date@@ -32,16 +32,11 @@ } deriving (Eq, Ord) instance Show DateTime where- show = fromMaybe "1970-01-01T00:00:00-00:00" . renderRfc3339 . unknown--instance Show (Local DateTime) where- show = fromMaybe "1970-01-01T00:00:00-00:00" . renderRfc3339--instance IsString DateTime where- fromString = utc . fromMaybe epoch . parseRfc3339+ show (DateTime d t)+ = show d ++ "T" ++ show t instance Epoch DateTime where- epoch = DateTime epoch midnight+ epoch = DateTime epoch epoch instance IsUnixTime DateTime where unixSeconds (DateTime d t)@@ -102,121 +97,100 @@ -- assumption: addSecondFractions for DateTime is always successful instance IsDate (Local DateTime) where- year (Local t Nothing)+ year (Local Nothing t) = year t- year (Local t (Just 0))+ year (Local (Just 0) t) = year t- year (Local t (Just o))+ year (Local (Just o) t) = year $ fromMaybe undefined $ addSecondFractions o t- month (Local t Nothing)+ month (Local Nothing t) = month t- month (Local t (Just 0))+ month (Local (Just 0) t) = month t- month (Local t (Just o))+ month (Local (Just o) t) = month $ fromMaybe undefined $ addSecondFractions o t- day (Local t Nothing)+ day (Local Nothing t) = day t- day (Local t (Just 0))+ day (Local (Just 0) t) = day t- day (Local t (Just o))+ day (Local (Just o) t) = day $ fromMaybe undefined $ addSecondFractions o t- setYear h (Local t o@Nothing)- = do t' <- setYear h t- return (Local t' o)- setYear h (Local t o@(Just 0))- = do t' <- setYear h t- return (Local t' o)- setYear h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setYear h >>= addSecondFractions (negate i)- return (Local t' o)- setMonth h (Local t o@Nothing)- = do t' <- setMonth h t- return (Local t' o)- setMonth h (Local t o@(Just 0))- = do t' <- setMonth h t- return (Local t' o)- setMonth h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setMonth h >>= addSecondFractions (negate i)- return (Local t' o)- setDay h (Local t o@Nothing)- = do t' <- setDay h t- return (Local t' o)- setDay h (Local t o@(Just 0))- = do t' <- setDay h t- return (Local t' o)- setDay h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setDay h >>= addSecondFractions (negate i)- return (Local t' o)+ setYear h (Local o@Nothing t)+ = Local o <$> setYear h t+ setYear h (Local o@(Just 0) t)+ = Local o <$> setYear h t+ setYear h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setYear h >>= addSecondFractions (negate i) )+ setMonth h (Local o@Nothing t)+ = Local o <$> setMonth h t+ setMonth h (Local o@(Just 0) t)+ = Local o <$> setMonth h t+ setMonth h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setMonth h >>= addSecondFractions (negate i) )+ setDay h (Local o@Nothing t)+ = Local o <$> setDay h t+ setDay h (Local o@(Just 0) t)+ = Local o <$> setDay h t+ setDay h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setDay h >>= addSecondFractions (negate i) ) -- assumption: addSecondFractions for DateTime is always successful instance IsTime (Local DateTime) where- hour (Local t Nothing)+ hour (Local Nothing t) = hour t- hour (Local t (Just 0))+ hour (Local (Just 0) t) = hour t- hour (Local t (Just o))+ hour (Local (Just o) t) = hour $ fromMaybe undefined $ addSecondFractions o t- minute (Local t Nothing)+ minute (Local Nothing t) = minute t- minute (Local t (Just 0))+ minute (Local (Just 0) t) = minute t- minute (Local t (Just o))+ minute (Local (Just o) t) = minute $ fromMaybe undefined $ addSecondFractions o t- second (Local t Nothing)+ second (Local Nothing t) = second t- second (Local t (Just 0))+ second (Local (Just 0) t) = second t- second (Local t (Just o))+ second (Local (Just o) t) = second $ fromMaybe undefined $ addSecondFractions o t- secondFraction (Local t Nothing)+ secondFraction (Local Nothing t) = secondFraction t- secondFraction (Local t (Just 0))+ secondFraction (Local (Just 0) t) = secondFraction t- secondFraction (Local t (Just o))+ secondFraction (Local (Just o) t) = secondFraction $ fromMaybe undefined $ addSecondFractions o t- setHour h (Local t o@Nothing)- = do t' <- setHour h t- return (Local t' o)- setHour h (Local t o@(Just 0))- = do t' <- setHour h t- return (Local t' o)- setHour h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setHour h >>= addSecondFractions (negate i)- return (Local t' o)- setMinute h (Local t o@Nothing)- = do t' <- setMinute h t- return (Local t' o)- setMinute h (Local t o@(Just 0))- = do t' <- setMinute h t- return (Local t' o)- setMinute h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setMinute h >>= addSecondFractions (negate i)- return (Local t' o)- setSecond h (Local t o@Nothing)- = do t' <- setSecond h t- return (Local t' o)- setSecond h (Local t o@(Just 0))- = do t' <- setSecond h t- return (Local t' o)- setSecond h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setSecond h >>= addSecondFractions (negate i)- return (Local t' o)- setSecondFraction h (Local t o@Nothing)- = do t' <- setSecondFraction h t- return (Local t' o)- setSecondFraction h (Local t o@(Just 0))- = do t' <- setSecondFraction h t- return (Local t' o)- setSecondFraction h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setSecondFraction h >>= addSecondFractions (negate i)- return (Local t' o)+ setHour h (Local o@Nothing t)+ = Local o <$> setHour h t+ setHour h (Local o@(Just 0) t)+ = Local o <$> setHour h t+ setHour h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setHour h >>= addSecondFractions (negate i) )+ setMinute h (Local o@Nothing t)+ = Local o <$> setMinute h t+ setMinute h (Local o@(Just 0) t)+ = Local o <$> setMinute h t+ setMinute h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setMinute h >>= addSecondFractions (negate i) )+ setSecond h (Local o@Nothing t)+ = Local o <$> setSecond h t+ setSecond h (Local o@(Just 0) t)+ = Local o <$> setSecond h t+ setSecond h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setSecond h >>= addSecondFractions (negate i) )+ setSecondFraction h (Local o@Nothing t)+ = Local o <$> setSecondFraction h t+ setSecondFraction h (Local o@(Just 0) t)+ = Local o <$> setSecondFraction h t+ setSecondFraction h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setSecondFraction h >>= addSecondFractions (negate i) ) -- This one is necessary to override, because the overflow should -- ripple into the date part.
+ Data/UTC/Type/Exception.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE DeriveDataTypeable #-}+module Data.UTC.Type.Exception where++import Control.Exception++import Data.Typeable++-- | All non-total functions within this library throw a 'UtcException' exception+-- within a 'Control.Monad.Catch.MonadThrow' context. Use 'Control.Monad.Catch.MonadCatch'+-- to specifically catch this exception.+--+-- The 'Prelude.String' contains information that might be+-- useful for debugging, but its specific form is undefined and must not be relied on.+data UtcException+ = UtcException String+ deriving (Show, Typeable)++instance Exception UtcException
Data/UTC/Type/Local.hs view
@@ -1,13 +1,11 @@ {-# LANGUAGE Safe, FlexibleInstances #-} module Data.UTC.Type.Local ( Local (..)- , unknown ) where import Data.Maybe import Data.UTC.Class.Epoch-import Data.UTC.Class.Midnight import Data.UTC.Class.IsTime import Data.UTC.Type.Time @@ -18,109 +16,87 @@ -- summer or winter time into account. data Local time = Local - { -- | The time to be interpreted as UTC+00:00 (__W__estern __E__uropean __T__ime)- utc :: time- , -- | ['Nothing'] The local offset is unknown (behaves like __W__estern __E__uropean __T__ime)+ { -- | ['Nothing'] The local offset is unknown (behaves like __W__estern __E__uropean __T__ime) -- -- ['Just' 0] UTC+00:00 (__W__estern __E__uropean __T__ime) -- -- ['Just' 3600] UTC+01:00 (__C__entral __E__uropean __T__ime) offset :: Maybe Rational+ -- | The time to be interpreted as UTC+00:00 (__W__estern __E__uropean __T__ime)+ , utc :: time } instance Eq t => Eq (Local t) where- (==) (Local a _) (Local b _)+ (==) (Local _ a) (Local _ b) = a == b instance Ord t => Ord (Local t) where- compare (Local a _) (Local b _)+ compare (Local _ a) (Local _ b) = compare a b instance Epoch t => Epoch (Local t) where epoch- = unknown epoch--instance Midnight t => Midnight (Local t) where- midnight- = unknown midnight+ = Local Nothing epoch instance Functor Local where- fmap f (Local t o)- = Local (f t) o+ fmap f (Local o t)+ = Local o (f t) instance Bounded t => Bounded (Local t) where- minBound = unknown minBound- maxBound = unknown maxBound+ minBound = Local Nothing minBound+ maxBound = Local Nothing maxBound -- assumption: addSecondFractions for Time is always successful instance IsTime (Local Time) where- hour (Local t Nothing)+ hour (Local Nothing t) = hour t- hour (Local t (Just 0))+ hour (Local (Just 0) t) = hour t- hour (Local t (Just o))+ hour (Local (Just o) t) = hour $ fromMaybe undefined $ addSecondFractions o t- minute (Local t Nothing)+ minute (Local Nothing t) = minute t- minute (Local t (Just 0))+ minute (Local (Just 0) t) = minute t- minute (Local t (Just o))+ minute (Local (Just o) t) = minute $ fromMaybe undefined $ addSecondFractions o t- second (Local t Nothing)+ second (Local Nothing t) = second t- second (Local t (Just 0))+ second (Local (Just 0) t) = second t- second (Local t (Just o))+ second (Local (Just o) t) = second $ fromMaybe undefined $ addSecondFractions o t- secondFraction (Local t Nothing)+ secondFraction (Local Nothing t) = secondFraction t- secondFraction (Local t (Just 0))+ secondFraction (Local (Just 0) t) = secondFraction t- secondFraction (Local t (Just o))+ secondFraction (Local (Just o) t) = secondFraction $ fromMaybe undefined $ addSecondFractions o t- setHour h (Local t o@Nothing)- = do t' <- setHour h t- return (Local t' o)- setHour h (Local t o@(Just 0))- = do t' <- setHour h t- return (Local t' o)- setHour h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setHour h >>= addSecondFractions (negate i)- return (Local t' o)- setMinute h (Local t o@Nothing)- = do t' <- setMinute h t- return (Local t' o)- setMinute h (Local t o@(Just 0))- = do t' <- setMinute h t- return (Local t' o)- setMinute h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setMinute h >>= addSecondFractions (negate i)- return (Local t' o)- setSecond h (Local t o@Nothing)- = do t' <- setSecond h t- return (Local t' o)- setSecond h (Local t o@(Just 0))- = do t' <- setSecond h t- return (Local t' o)- setSecond h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setSecond h >>= addSecondFractions (negate i)- return (Local t' o)- setSecondFraction h (Local t o@Nothing)- = do t' <- setSecondFraction h t- return (Local t' o)- setSecondFraction h (Local t o@(Just 0))- = do t' <- setSecondFraction h t- return (Local t' o)- setSecondFraction h (Local t o@(Just i))- = do t' <- addSecondFractions i t >>= setSecondFraction h >>= addSecondFractions (negate i)- return (Local t' o)----unknown :: t -> Local t-unknown t- = Local t Nothing+ setHour h (Local o@Nothing t)+ = Local o <$> setHour h t+ setHour h (Local o@(Just 0) t)+ = Local o <$> setHour h t+ setHour h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setHour h >>= addSecondFractions (negate i) )+ setMinute h (Local o@Nothing t)+ = Local o <$> setMinute h t+ setMinute h (Local o@(Just 0) t)+ = Local o <$> setMinute h t+ setMinute h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setMinute h >>= addSecondFractions (negate i) )+ setSecond h (Local o@Nothing t)+ = Local o <$> setSecond h t+ setSecond h (Local o@(Just 0) t)+ = Local o <$> setSecond h t+ setSecond h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setSecond h >>= addSecondFractions (negate i) )+ setSecondFraction h (Local o@Nothing t)+ = Local o <$> setSecondFraction h t+ setSecondFraction h (Local o@(Just 0) t)+ = Local o <$> setSecondFraction h t+ setSecondFraction h (Local o@(Just i) t)+ = Local o <$> ( addSecondFractions i t >>= setSecondFraction h >>= addSecondFractions (negate i) )
Data/UTC/Type/Time.hs view
@@ -1,33 +1,49 @@ module Data.UTC.Type.Time ( Time ()- , midnight ) where +import Control.Monad.Catch+ import Data.Ratio -import Data.UTC.Class.Midnight+import Data.UTC.Class.Epoch import Data.UTC.Class.IsTime import Data.UTC.Class.IsUnixTime import Data.UTC.Internal+import Data.UTC.Type.Exception -- | This type represents time instants during a day (__00:00:00 - 23:59:59.999__..) -- with arbitrary precision (uses 'Prelude.Integer' internally). -- -- * The internal structure is not exposed to avoid the creation of -- invalid values.--- Use 'Data.UTC.midnight' or a parser to construct values.+-- Use 'Data.UTC.epoch' or a parser to construct values. -- * The instance of 'Prelude.Show' is only meant for debugging purposes -- and is subject to change.+--+-- > > show (epoch :: Time)+-- > 00:00:00 data Time = Time { tHour :: Integer , tMinute :: Integer , tSecond :: Integer , tSecondFraction :: Rational- } deriving (Eq, Ord, Show)+ } deriving (Eq, Ord) -instance Midnight Time where- midnight+instance Show Time where+ show (Time hh mm ss ff)+ = concat+ [ fixedDecimal 2 hh+ , ":"+ , fixedDecimal 2 mm+ , ":"+ , fixedDecimal 2 ss+ , decimalFraction 12 ff+ ]++instance Epoch Time where+ epoch = Time 0 0 0 0 instance IsUnixTime Time where@@ -55,14 +71,14 @@ = tSecondFraction setHour x t- | x < 0 || 23 < x = fail $ "Time.setHour " ++ show x+ | x < 0 || 23 < x = throwM $ UtcException $ "Time: setHour " ++ show x ++ " " ++ show t | otherwise = return $ t { tHour = x } setMinute x t- | x < 0 || 59 < x = fail $ "Time.setMinute " ++ show x+ | x < 0 || 59 < x = throwM $ UtcException $ "Time: setMinute " ++ show x ++ " " ++ show t | otherwise = return $ t { tMinute = x } setSecond x t- | x < 0 || 59 < x = fail $ "Time.setSecond " ++ show x+ | x < 0 || 59 < x = throwM $ UtcException $ "Time: setSecond " ++ show x ++ " " ++ show t | otherwise = return $ t { tSecond = x } setSecondFraction x t- | x < 0 || 1 <= x = fail $ "Time.setSecondFraction " ++ show x+ | x < 0 || 1 <= x = throwM $ UtcException $ "Time: setSecondFraction " ++ show x ++ " " ++ show t | otherwise = return $ t { tSecondFraction = x }
tests/Test.hs view
@@ -5,8 +5,6 @@ import Test.Framework (Test) import Test.Framework.Providers.QuickCheck2 (testProperty) -import Data.String- import Data.UTC import Data.UTC.Internal.Test (test)@@ -22,7 +20,7 @@ , testGroup "instance Time DateTime" $ testTimeInstance (epoch :: DateTime) , testGroup "instance Time Time"- $ testTimeInstance (midnight :: Time)+ $ testTimeInstance (epoch :: Time) , Data.UTC.Internal.Test.test , Data.UTC.Class.IsDate.Test.test@@ -125,12 +123,12 @@ , ("10", setSecondFraction 1.1 t) ] -testUnixTimeInstance :: (Show t, IsUnixTime t, IsString t,Eq t) => t -> [Test]+testUnixTimeInstance :: (Show t, IsUnixTime t, Eq t, IsTime t, IsDate t) => t -> [Test] testUnixTimeInstance t = (map (\(i64,s)-> testProperty ("fromUnixSeconds " ++ show i64 ++ ") == Just " ++ show s)- $ (fromUnixSeconds i64) === Just (fromString s `asTypeOf` t)+ $ (fromUnixSeconds i64) === (utc `fmap` parseRfc3339 s) `asTypeOf` Just t ) unixEpochMsRfc3339TimeTuples )@@ -138,7 +136,7 @@ (map (\(i64,s)-> testProperty ("unixSeconds (" ++ show s ++ ") == " ++ show i64)- $ unixSeconds (fromString s `asTypeOf` t) === i64+ $ unixSeconds `fmap` ((utc `fmap` parseRfc3339 s) `asTypeOf` Just t) === Just i64 ) unixEpochMsRfc3339TimeTuples )
utc.cabal view
@@ -1,5 +1,5 @@ name: utc-version: 0.1.0.1+version: 0.2.0.0 stability: experimental synopsis: A pragmatic time and date library. description: This library aims to supply you with common@@ -15,12 +15,6 @@ specific or maybe more efficient time and date types. Implement the interfaces and get all the parsing and rendering functions for free! .- This is a work in progress!- .- Try it out and play with it. Tell me what you think- about the API design and naming, but __DON'T USE IT- IN PRODUCTION YET!__- . Bug reports or (even better) tests are welcome. license: MIT license-file: LICENSE@@ -39,13 +33,13 @@ , bytestring >= 0.10.4.0 , attoparsec , clock >= 0.3 && < 0.5+ , exceptions >= 0.4 ghc-options: -Wall hs-source-dirs: . default-language: Haskell98 exposed-modules: Data.UTC- , Data.UTC.Class+ other-modules: Data.UTC.Class , Data.UTC.Class.Epoch- , Data.UTC.Class.Midnight , Data.UTC.Class.IsDate , Data.UTC.Class.IsTime , Data.UTC.Class.IsUnixTime@@ -55,9 +49,11 @@ , Data.UTC.Type.Time , Data.UTC.Type.DateTime , Data.UTC.Type.Local+ , Data.UTC.Type.Exception , Data.UTC.Format.Rfc3339+ , Data.UTC.Format.Iso8601 , Data.UTC.Internal- other-modules: Data.UTC.Format.Rfc3339.Parser+ , Data.UTC.Format.Rfc3339.Parser , Data.UTC.Format.Rfc3339.Builder Test-Suite test@@ -66,9 +62,9 @@ ghc-options: -Wall -O2 hs-source-dirs: tests . other-modules: Data.UTC+ -- in library unexposed modules , Data.UTC.Class , Data.UTC.Class.Epoch- , Data.UTC.Class.Midnight , Data.UTC.Class.IsDate , Data.UTC.Class.IsDate.Test , Data.UTC.Class.IsTime@@ -79,8 +75,9 @@ , Data.UTC.Type.Time , Data.UTC.Type.DateTime , Data.UTC.Type.Local+ , Data.UTC.Type.Exception , Data.UTC.Format.Rfc3339- -- in library unexposed modules+ , Data.UTC.Format.Iso8601 , Data.UTC.Format.Rfc3339.Parser , Data.UTC.Format.Rfc3339.Builder , Data.UTC.Internal@@ -90,6 +87,7 @@ , bytestring >= 0.10.4.0 , attoparsec , clock >= 0.3 && < 0.5+ , exceptions >= 0.4 -- additional deps for testing , Cabal , test-framework >= 0.8.0.2