{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_HADDOCK hide #-}
module Data.Time.LocalTime.TimeZone.Olson.Parse
(
getTimeZoneSeriesFromOlsonFile,
getOlsonFromFile,
olsonToTimeZoneSeries,
getOlson,
OlsonError
)
where
import Data.Time.LocalTime.TimeZone.Olson.Types
import Data.Time.LocalTime.TimeZone.Series (TimeZoneSeries(..))
import Data.Time (TimeZone(TimeZone))
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Data.Binary.Get (Get, runGet, getWord8, getWord32be, getWord64be,
getByteString, getRemainingLazyByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Monoid (mappend)
import Data.List (sortBy, groupBy)
import Data.Maybe (listToMaybe, fromMaybe)
import Data.Word (Word8)
import Data.Int (Int32, Int64)
import Data.Ord (comparing)
import Data.Function (on)
import Data.Typeable (Typeable)
import Control.Monad (guard, replicateM, replicateM_, when)
import Control.Exception.Extensible (try, throw, Exception, ErrorCall)
data OlsonError = OlsonError String
deriving Typeable
instance Show OlsonError where
show :: OlsonError -> String
show (OlsonError String
msg) = String
msg
instance Exception OlsonError
olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
olsonToTimeZoneSeries (OlsonData [Transition]
ttimes ttinfos :: [TtInfo String]
ttinfos@(TtInfo String
dflt0:[TtInfo String]
_) [LeapInfo]
_ Maybe String
_) =
([(UTCTime, TimeZone)] -> TimeZoneSeries)
-> Maybe [(UTCTime, TimeZone)] -> Maybe TimeZoneSeries
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (TimeZone -> [(UTCTime, TimeZone)] -> TimeZoneSeries
TimeZoneSeries (TimeZone -> [(UTCTime, TimeZone)] -> TimeZoneSeries)
-> TimeZone -> [(UTCTime, TimeZone)] -> TimeZoneSeries
forall a b. (a -> b) -> a -> b
$ TtInfo String -> TimeZone
mkTZ TtInfo String
dflt) (Maybe [(UTCTime, TimeZone)] -> Maybe TimeZoneSeries)
-> ([Transition] -> Maybe [(UTCTime, TimeZone)])
-> [Transition]
-> Maybe TimeZoneSeries
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Transition -> Maybe (UTCTime, TimeZone))
-> [Transition] -> Maybe [(UTCTime, TimeZone)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ([TtInfo String] -> Transition -> Maybe (UTCTime, TimeZone)
lookupTZ [TtInfo String]
ttinfos) ([Transition] -> Maybe [(UTCTime, TimeZone)])
-> ([Transition] -> [Transition])
-> [Transition]
-> Maybe [(UTCTime, TimeZone)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
[Transition] -> [Transition]
uniqTimes ([Transition] -> [Transition])
-> ([Transition] -> [Transition]) -> [Transition] -> [Transition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Transition -> Transition -> Ordering)
-> [Transition] -> [Transition]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy Transition -> Transition -> Ordering
futureToPast ([Transition] -> Maybe TimeZoneSeries)
-> [Transition] -> Maybe TimeZoneSeries
forall a b. (a -> b) -> a -> b
$ [Transition]
ttimes
where
dflt :: TtInfo String
dflt = TtInfo String -> Maybe (TtInfo String) -> TtInfo String
forall a. a -> Maybe a -> a
fromMaybe TtInfo String
dflt0 (Maybe (TtInfo String) -> TtInfo String)
-> ([TtInfo String] -> Maybe (TtInfo String))
-> [TtInfo String]
-> TtInfo String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TtInfo String] -> Maybe (TtInfo String)
forall a. [a] -> Maybe a
listToMaybe ([TtInfo String] -> TtInfo String)
-> [TtInfo String] -> TtInfo String
forall a b. (a -> b) -> a -> b
$ (TtInfo String -> Bool) -> [TtInfo String] -> [TtInfo String]
forall a. (a -> Bool) -> [a] -> [a]
filter TtInfo String -> Bool
forall {abbr}. TtInfo abbr -> Bool
isStd [TtInfo String]
ttinfos
isStd :: TtInfo abbr -> Bool
isStd (TtInfo Int
_ Bool
isdst TransitionType
_ abbr
_) = Bool -> Bool
not Bool
isdst
mkTZ :: TtInfo String -> TimeZone
mkTZ (TtInfo Int
utoff Bool
isdst TransitionType
_ String
abbr) =
Int -> Bool -> String -> TimeZone
TimeZone ((Int
utoff Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
30) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
60) Bool
isdst String
abbr
lookupTZ :: [TtInfo String] -> Transition -> Maybe (UTCTime, TimeZone)
lookupTZ [TtInfo String]
ttinfos Transition
ttime = (TtInfo String -> (UTCTime, TimeZone))
-> Maybe (TtInfo String) -> Maybe (UTCTime, TimeZone)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((,) (UTCTime -> TimeZone -> (UTCTime, TimeZone))
-> UTCTime -> TimeZone -> (UTCTime, TimeZone)
forall a b. (a -> b) -> a -> b
$ Transition -> UTCTime
toUTC Transition
ttime) (TimeZone -> (UTCTime, TimeZone))
-> (TtInfo String -> TimeZone)
-> TtInfo String
-> (UTCTime, TimeZone)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TtInfo String -> TimeZone
mkTZ) (Maybe (TtInfo String) -> Maybe (UTCTime, TimeZone))
-> ([TtInfo String] -> Maybe (TtInfo String))
-> [TtInfo String]
-> Maybe (UTCTime, TimeZone)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TtInfo String] -> Maybe (TtInfo String)
forall a. [a] -> Maybe a
listToMaybe ([TtInfo String] -> Maybe (UTCTime, TimeZone))
-> [TtInfo String] -> Maybe (UTCTime, TimeZone)
forall a b. (a -> b) -> a -> b
$
Int -> [TtInfo String] -> [TtInfo String]
forall a. Int -> [a] -> [a]
drop (Transition -> Int
transIndex Transition
ttime) [TtInfo String]
ttinfos
toUTC :: Transition -> UTCTime
toUTC = POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime)
-> (Transition -> POSIXTime) -> Transition -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> POSIXTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> POSIXTime)
-> (Transition -> Integer) -> Transition -> POSIXTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Transition -> Integer
transTime
uniqTimes :: [Transition] -> [Transition]
uniqTimes = ([Transition] -> Transition) -> [[Transition]] -> [Transition]
forall a b. (a -> b) -> [a] -> [b]
map [Transition] -> Transition
forall a. HasCallStack => [a] -> a
last ([[Transition]] -> [Transition])
-> ([Transition] -> [[Transition]]) -> [Transition] -> [Transition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Transition -> Transition -> Bool)
-> [Transition] -> [[Transition]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Integer -> Integer -> Bool)
-> (Transition -> Integer) -> Transition -> Transition -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Transition -> Integer
transTime)
futureToPast :: Transition -> Transition -> Ordering
futureToPast = (Transition -> Integer) -> Transition -> Transition -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing ((Transition -> Integer) -> Transition -> Transition -> Ordering)
-> (Transition -> Integer) -> Transition -> Transition -> Ordering
forall a b. (a -> b) -> a -> b
$ Integer -> Integer
forall a. Num a => a -> a
negate (Integer -> Integer)
-> (Transition -> Integer) -> Transition -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Transition -> Integer
transTime
olsonToTimeZoneSeries OlsonData
_ = Maybe TimeZoneSeries
forall a. Maybe a
Nothing
getTimeZoneSeriesFromOlsonFile :: FilePath -> IO TimeZoneSeries
getTimeZoneSeriesFromOlsonFile :: String -> IO TimeZoneSeries
getTimeZoneSeriesFromOlsonFile String
fp = String -> IO OlsonData
getOlsonFromFile String
fp IO OlsonData
-> (OlsonData -> IO TimeZoneSeries) -> IO TimeZoneSeries
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
IO TimeZoneSeries
-> (TimeZoneSeries -> IO TimeZoneSeries)
-> Maybe TimeZoneSeries
-> IO TimeZoneSeries
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> String -> IO TimeZoneSeries
forall a. String -> String -> IO a
throwOlson String
fp String
"no timezone found in OlsonData") TimeZoneSeries -> IO TimeZoneSeries
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TimeZoneSeries -> IO TimeZoneSeries)
-> (OlsonData -> Maybe TimeZoneSeries)
-> OlsonData
-> IO TimeZoneSeries
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
OlsonData -> Maybe TimeZoneSeries
olsonToTimeZoneSeries
getOlsonFromFile :: FilePath -> IO OlsonData
getOlsonFromFile :: String -> IO OlsonData
getOlsonFromFile String
fp = do
e <- IO OlsonData -> IO (Either ErrorCall OlsonData)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO OlsonData -> IO (Either ErrorCall OlsonData))
-> (IO ByteString -> IO OlsonData)
-> IO ByteString
-> IO (Either ErrorCall OlsonData)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> OlsonData) -> IO ByteString -> IO OlsonData
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Get OlsonData -> ByteString -> OlsonData
forall a. Get a -> ByteString -> a
runGet (Get OlsonData -> ByteString -> OlsonData)
-> Get OlsonData -> ByteString -> OlsonData
forall a b. (a -> b) -> a -> b
$ SizeLimits -> Get OlsonData
getOlson SizeLimits
defaultLimits) (IO ByteString -> IO (Either ErrorCall OlsonData))
-> IO ByteString -> IO (Either ErrorCall OlsonData)
forall a b. (a -> b) -> a -> b
$ String -> IO ByteString
L.readFile String
fp
either (formatError fp) return e
formatError :: FilePath -> ErrorCall -> IO a
formatError :: forall a. String -> ErrorCall -> IO a
formatError String
fp ErrorCall
e = String -> String -> IO a
forall a. String -> String -> IO a
throwOlson String
fp (String -> IO a) -> String -> IO a
forall a b. (a -> b) -> a -> b
$ ErrorCall -> String
forall a. Show a => a -> String
show ErrorCall
e
getOlson :: SizeLimits -> Get OlsonData
getOlson :: SizeLimits -> Get OlsonData
getOlson SizeLimits
limits = do
(version, part1) <- Bool -> SizeLimits -> Get Integer -> Get (Word8, OlsonData)
forall a.
Integral a =>
Bool -> SizeLimits -> Get a -> Get (Word8, OlsonData)
getOlsonPart Bool
True SizeLimits
limits Get Integer
get32bitInteger
case () of
()
_ | Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0 -> OlsonData -> Get OlsonData
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return OlsonData
part1
| Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
50 Bool -> Bool -> Bool
|| Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
51 -> do
(_, part2) <- Bool -> SizeLimits -> Get Integer -> Get (Word8, OlsonData)
forall a.
Integral a =>
Bool -> SizeLimits -> Get a -> Get (Word8, OlsonData)
getOlsonPart Bool
False SizeLimits
limits Get Integer
get64bitInteger
posixTZ <- getPosixTZ
return $ part1 `mappend` part2 `mappend` posixTZ
| Bool
otherwise -> do
let msg :: String
msg = String
"getOlson: invalid tzfile version " String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Word8] -> String
toASCII [Word8
version]
(OlsonData -> Bool) -> String -> OlsonData -> Get OlsonData
forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> String -> a -> m a
verify (Bool -> OlsonData -> Bool
forall a b. a -> b -> a
const Bool
False) String
msg OlsonData
forall a. HasCallStack => a
undefined
getOlsonPart :: Integral a => Bool -> SizeLimits -> Get a ->
Get (Word8, OlsonData)
getOlsonPart :: forall a.
Integral a =>
Bool -> SizeLimits -> Get a -> Get (Word8, OlsonData)
getOlsonPart Bool
verifyMagic SizeLimits
limits Get a
getTime = do
magic <- (ByteString -> String) -> Get ByteString -> Get String
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Word8] -> String
toASCII ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack) (Get ByteString -> Get String) -> Get ByteString -> Get String
forall a b. (a -> b) -> a -> b
$ Int -> Get ByteString
getByteString Int
4
when verifyMagic $ verify_ (== "TZif") "missing magic number" magic
version <- getWord8
replicateM_ 15 getWord8
tzh_ttisutcnt <- get32bitInt
tzh_ttisstdcnt <- get32bitInt
tzh_leapcnt <- get32bitInt
>>= verify (withinLimit maxLeaps) "too many leap second specifications"
tzh_timecnt <- get32bitInt
>>= verify (withinLimit maxTimes) "too many timezone transitions"
tzh_typecnt <- get32bitInt
>>= verify (withinLimit maxTypes) "too many timezone type specifications"
verify (withinLimit maxTypes) "too many isut specifiers" tzh_ttisutcnt
verify (withinLimit maxTypes) "too many isstd specifiers" tzh_ttisstdcnt
tzh_charcnt <- get32bitInt
>>= verify (withinLimit maxAbbrChars) "too many tilezone specifiers"
times <- fmap (map toInteger) $ replicateM tzh_timecnt getTime
indexes <- replicateM tzh_timecnt get8bitInt
ttinfos <- replicateM tzh_typecnt getTtInfo
abbr_chars <- fmap (toASCII . B.unpack) $ getByteString tzh_charcnt
leaps <- replicateM tzh_leapcnt $ getLeapInfo getTime
isstds <- replicateM tzh_ttisstdcnt getBool
isuts <- replicateM tzh_ttisutcnt getBool
return
(version,
OlsonData
(zipWith Transition times indexes)
(map (flip lookupAbbr abbr_chars) . zipWith setTtype ttinfos $
zipWith boolsToTType
(isstds ++ repeat False) (isuts ++ repeat False)
)
leaps
Nothing
)
where
withinLimit :: (SizeLimits -> Maybe a) -> a -> Bool
withinLimit SizeLimits -> Maybe a
limit a
value = Bool -> (a -> Bool) -> Maybe a -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (a
value a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<=) (Maybe a -> Bool) -> Maybe a -> Bool
forall a b. (a -> b) -> a -> b
$ SizeLimits -> Maybe a
limit SizeLimits
limits
lookupAbbr :: TtInfo Int -> String -> TtInfo String
lookupAbbr (TtInfo Int
utoff Bool
isdst TransitionType
ttype Int
abbrind) =
Int -> Bool -> TransitionType -> String -> TtInfo String
forall abbr. Int -> Bool -> TransitionType -> abbr -> TtInfo abbr
TtInfo Int
utoff Bool
isdst TransitionType
ttype (String -> TtInfo String) -> ShowS -> String -> TtInfo String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\NUL') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
abbrind
setTtype :: TtInfo abbr -> TransitionType -> TtInfo abbr
setTtype TtInfo abbr
ttinfo TransitionType
ttype = TtInfo abbr
ttinfo {tt_ttype = ttype}
boolsToTType :: Bool -> Bool -> TransitionType
boolsToTType Bool
_ Bool
isut | Bool
isut = TransitionType
UTC
boolsToTType Bool
isstd Bool
_
| Bool
isstd = TransitionType
Std
| Bool
otherwise = TransitionType
Wall
getPosixTZ :: Get OlsonData
getPosixTZ :: Get OlsonData
getPosixTZ = do
Get Word8
getWord8 Get Word8 -> (Word8 -> Get Word8) -> Get Word8
forall a b. Get a -> (a -> Get b) -> Get b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Word8 -> Bool) -> String -> Word8 -> Get Word8
forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> String -> a -> m a
verify (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
10)
String
"POSIX TZ string not preceded by newline"
posixTZ <- (ByteString -> ByteString) -> Get ByteString -> Get ByteString
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Word8 -> Bool) -> ByteString -> ByteString
L.takeWhile (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
10)) Get ByteString
getRemainingLazyByteString
return . OlsonData [] [] [] $ do
guard (not $ L.null posixTZ)
Just . toASCII $ L.unpack posixTZ
getTtInfo :: Get (TtInfo Int)
getTtInfo :: Get (TtInfo Int)
getTtInfo = do
utoff <- Get Int
get32bitInt
isdst <- getBool
abbrind <- get8bitInt
return $ TtInfo utoff isdst Wall abbrind
getLeapInfo :: Integral a => Get a -> Get LeapInfo
getLeapInfo :: forall a. Integral a => Get a -> Get LeapInfo
getLeapInfo Get a
getTime = do
lTime <- (a -> Integer) -> Get a -> Get Integer
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Integer
forall a. Integral a => a -> Integer
toInteger Get a
getTime
lOffset <- get32bitInt
return $ LeapInfo lTime lOffset
get8bitInt :: Get Int
get8bitInt :: Get Int
get8bitInt = (Word8 -> Int) -> Get Word8 -> Get Int
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Word8
getWord8
getInt32 :: Get Int32
getInt32 :: Get Int32
getInt32 = (Word32 -> Int32) -> Get Word32 -> Get Int32
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Word32
getWord32be
get32bitInt :: Get Int
get32bitInt :: Get Int
get32bitInt = (Int32 -> Int) -> Get Int32 -> Get Int
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Int32
getInt32
get32bitInteger :: Get Integer
get32bitInteger :: Get Integer
get32bitInteger = (Int32 -> Integer) -> Get Int32 -> Get Integer
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int32 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Int32
getInt32
getInt64 :: Get Int64
getInt64 :: Get Int64
getInt64 = (Word64 -> Int64) -> Get Word64 -> Get Int64
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Word64
getWord64be
get64bitInteger :: Get Integer
get64bitInteger :: Get Integer
get64bitInteger = (Int64 -> Integer) -> Get Int64 -> Get Integer
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int64 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Get Int64
getInt64
getBool :: Get Bool
getBool :: Get Bool
getBool = (Word8 -> Bool) -> Get Word8 -> Get Bool
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) Get Word8
getWord8
toASCII :: [Word8] -> String
toASCII :: [Word8] -> String
toASCII = (Word8 -> Char) -> [Word8] -> String
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> (Word8 -> Int) -> Word8 -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral)
verify :: Monad m => (a -> Bool) -> String -> a -> m a
verify :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> String -> a -> m a
verify a -> Bool
pred String
msg a
val
| a -> Bool
pred a
val = a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
val
| Bool
otherwise = String -> m a
forall a. HasCallStack => String -> a
error String
msg
verify_ :: Monad m => (a -> Bool) -> String -> a -> m ()
verify_ :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> String -> a -> m ()
verify_ a -> Bool
pred String
msg a
val
| a -> Bool
pred a
val = () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
otherwise = String -> m ()
forall a. HasCallStack => String -> a
error String
msg
throwOlson :: FilePath -> String -> IO a
throwOlson :: forall a. String -> String -> IO a
throwOlson String
fp String
msg = OlsonError -> IO a
forall a e. (HasCallStack, Exception e) => e -> a
throw (OlsonError -> IO a) -> (String -> OlsonError) -> String -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> OlsonError
OlsonError (String -> IO a) -> String -> IO a
forall a b. (a -> b) -> a -> b
$
String
fp String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": invalid timezone file: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
msg