{-# LANGUAGE CPP, OverloadedStrings #-} -- | -- Formatting time is slow. -- This package provides mechanisms to cache formatted date. module Network.Wai.Logger.Date ( -- * Types DateCacheGetter , DateCacheUpdater , ZonedDate -- * Cache configuration , DateCacheConf(..) , zonedDateCacheConf -- * Date cacher , clockDateCacher ) where import Control.AutoUpdate (mkAutoUpdate, defaultUpdateSettings, updateAction) import Data.ByteString (ByteString) #if WINDOWS import qualified Data.ByteString.Char8 as BS import Data.Time (UTCTime, formatTime, getCurrentTime, utcToLocalZonedTime) # if MIN_VERSION_time(1,5,0) import Data.Time (defaultTimeLocale) # else import System.Locale (defaultTimeLocale) # endif #else import Data.UnixTime (formatUnixTime, fromEpochTime) import System.Posix (EpochTime, epochTime) #endif ---------------------------------------------------------------- -- | Getting cached 'ZonedDate'. type DateCacheGetter = IO ZonedDate -- | Updateing cached 'ZonedDate'. This should be called every second. -- See the source code of 'withStdoutLogger'. type DateCacheUpdater = IO () ---------------------------------------------------------------- -- | A type for zoned date. type ZonedDate = ByteString ---------------------------------------------------------------- data DateCacheConf t = DateCacheConf { -- | A function to get a time. E.g 'epochTime' and 'getCurrentTime'. getTime :: IO t -- | A function to format a time. , formatDate :: t -> IO ByteString } #if WINDOWS -- | Zoned date cacher using UTC. zonedDateCacheConf :: DateCacheConf UTCTime zonedDateCacheConf = DateCacheConf { getTime = getCurrentTime , formatDate = \ut -> do zt <- utcToLocalZonedTime ut return $ BS.pack $ formatTime defaultTimeLocale "%d/%b/%Y:%T %z" zt } #else -- | Zoned date cacher using UnixTime. zonedDateCacheConf :: DateCacheConf EpochTime zonedDateCacheConf = DateCacheConf { getTime = epochTime , formatDate = formatUnixTime "%d/%b/%Y:%T %z" . fromEpochTime } #endif ---------------------------------------------------------------- -- | -- Returning 'DateCacheGetter' and 'DateCacheUpdater'. -- -- Note: Since version 2.1.2, this function uses the auto-update package -- internally, and therefore the @DateCacheUpdater@ value returned need -- not be called. To wit, the return value is in fact an empty action. clockDateCacher :: IO (DateCacheGetter, DateCacheUpdater) clockDateCacher = do getter <- mkAutoUpdate defaultUpdateSettings { updateAction = getTime zonedDateCacheConf >>= formatDate zonedDateCacheConf } return (getter, return ())