hodatime-0.1.1.1: src/Data/HodaTime/TimeZone/Olson.hs
module Data.HodaTime.TimeZone.Olson
(
getTransitions
)
where
import Data.HodaTime.TimeZone.Internal
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Binary.Get (Get, getWord8, getWord32be, getByteString, runGetOrFail)
import Data.Word (Word8)
import Control.Monad (unless, replicateM_, replicateM, liftM, filterM)
import Data.Int (Int32)
import Control.Applicative ((<$>), (<*>), ZipList(..))
import Data.List (nub)
import System.Directory (doesFileExist, getDirectoryContents)
import System.FilePath ((</>))
import Data.HodaTime.Instant (fromSecondsSinceUnixEpoch)
import Data.HodaTime.Instant.Internal (Instant)
getTransitions :: L.ByteString -> Either String Transitions
getTransitions bs = case runGetOrFail getTransitions' bs of
Left (_, _, msg) -> Left msg
Right (_, _, xs) -> Right xs
where
getTransitions' = do
magic <- (toASCII . B.unpack) <$> getByteString 4
unless (magic == "TZif") (fail $ "unknown magic: " ++ magic) -- We could consider creating an error type for this
_version <- getWord8
replicateM_ 15 getWord8 -- skip reserved section
[ttisgmtcnt, ttisstdcnt, leapcnt, transcnt, ttypecnt, abbrlen] <- replicateM 6 get32bitInt
transitions <- replicateM transcnt $ fromSecondsSinceUnixEpoch <$> get32bitInt
indexes <- replicateM transcnt get8bitInt
ttypes <- replicateM ttypecnt $ (,,) <$> get32bitInt <*> getBool <*> get8bitInt
abbrs <- (toASCII . B.unpack) <$> getByteString abbrlen
_leaps <- replicateM leapcnt getLeapInfo
ttisstds <- replicateM ttisstdcnt getBool
ttisgmts <- replicateM ttisgmtcnt getBool
return $ zipTransitions (zipTransitionTypes abbrs ttypes ttisstds ttisgmts) transitions indexes
zipTransitionTypes :: String -> [(Int, Bool, Int)] -> [Bool] -> [Bool] -> [TransitionInfo]
zipTransitionTypes abbrs = zipWith3 toTI
where
toTI (gmt, isdst, offset) = TransitionInfo gmt isdst (getAbbr offset abbrs)
getAbbr offset = takeWhile (/= '\NUL') . drop offset
zipTransitions :: [TransitionInfo] -> [Instant] -> [Int] -> Transitions
zipTransitions tis trans = foldr (\(i, idx) im -> addTransitionInfo i (tis !! idx) im) mkTransitions . zip trans
getLeapInfo :: Get (Integer, Int)
getLeapInfo = do
lTime <- fmap toInteger get32bitInteger
lOffset <- get32bitInt
return (lTime, lOffset)
getBool :: Get Bool
getBool = fmap (/= 0) getWord8
get8bitInt :: Get Int
get8bitInt = fmap fromIntegral getWord8
getInt32 :: Get Int32
getInt32 = fmap fromIntegral getWord32be
get32bitInt :: Get Int
get32bitInt = fmap fromIntegral getInt32
get32bitInteger :: Get Integer
get32bitInteger = fmap fromIntegral getInt32
toASCII :: [Word8] -> String
toASCII = map (toEnum . fromIntegral)