{-# LANGUAGE TemplateHaskell #-} -- | -- Load TimeZoneSeries from an Olson file at compile time. -- -- For example: -- -- > myTimeZoneSeries :: TimeZoneSeries -- > myTimeZoneSeries = $(loadTZFile "/usr/share/zoneinfo/Europe/Stockholm") module Data.Time.LocalTime.TimeZone.Olson.TH ( loadTZFile ) where import Data.Ratio (numerator, denominator) import Data.Time.LocalTime.TimeZone.Olson (getTimeZoneSeriesFromOlsonFile) import Data.Time.LocalTime.TimeZone.Series (TimeZoneSeries(..)) import Data.Time.LocalTime (TimeZone(..)) import Data.Time (UTCTime(..), Day(..), DiffTime, secondsToDiffTime) import Language.Haskell.TH (Q, runIO, Exp(..), mkName, Lit(..), litE, integerL) -- | Make a splice of a TimeZoneSeries from an Olson file. loadTZFile :: FilePath -- ^ Path to the Olson file. -> Q Exp loadTZFile zf = mkTZS =<< (runIO $ getTimeZoneSeriesFromOlsonFile zf) -- | Make a splice of a TimeZoneSeries. mkTZS :: TimeZoneSeries -- ^ The TimeZoneSeries to be spliced -> Q Exp mkTZS (TimeZoneSeries def tlist) = [| TimeZoneSeries $(litTimeZone def) $(mkList tlist) |] mkList :: [(UTCTime,TimeZone)] -> Q Exp mkList l = [| $(fmap ListE $ mapM mkPair l) |] mkPair :: (UTCTime,TimeZone) -> Q Exp mkPair (t,tz) = [| ($(litUTCTime t),$(litTimeZone tz)) |] litUTCTime :: UTCTime -> Q Exp litUTCTime (UTCTime (ModifiedJulianDay d) s) = [| UTCTime (ModifiedJulianDay $(litInteger d)) (secondsToDiffTime $(litInteger $ diffTimeToInteger s)) |] litInteger :: Integer -> Q Exp litInteger = litE . integerL diffTimeToInteger :: DiffTime -> Integer diffTimeToInteger s = let r = toRational s n = numerator r d = denominator r in (n `div` d) litTimeZone :: TimeZone -> Q Exp litTimeZone (TimeZone m s n) = [| TimeZone $(litInteger $ toInteger m) $(return $ ConE $ mkName $ show s) $(litE $ StringL n) |]