diff --git a/Network/Wai/Logger/Date.hs b/Network/Wai/Logger/Date.hs
--- a/Network/Wai/Logger/Date.hs
+++ b/Network/Wai/Logger/Date.hs
@@ -1,50 +1,52 @@
-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DoAndIfThenElse, BangPatterns #-}
 
 module Network.Wai.Logger.Date (
     ZonedDate
+  , DateRef
   , dateInit
   , getDate
-  , DateRef
   ) where
 
-import Control.Concurrent
-import Control.DeepSeq
+import Control.Applicative
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as BS
 import Data.IORef
 import Data.Time
 import System.Locale
+import System.Posix (EpochTime, epochTime)
+import Data.Time.Clock.POSIX
 
 -- | A type for zoned date.
 type ZonedDate = ByteString
 
--- | Reference to the cache of 'ZoneDate'.
-newtype DateRef = DateRef (IORef ByteString)
+data DateCache = DateCache {
+    unixTime :: !EpochTime
+  , zonedDate :: !ZonedDate
+  }
 
--- | Getting 'ZonedDate' from the cache.
-getDate :: DateRef -> IO ZonedDate
-getDate (DateRef ref) = readIORef ref
+-- | Reference to the 'ZonedDate' cache.
+newtype DateRef = DateRef (IORef DateCache)
 
--- | Start caching 'ZonedDate' every second.
-dateInit :: IO DateRef
-dateInit = do
-    ref <- formatDate >>= newIORef
-    let dateref = DateRef ref
-    forkIO $ date dateref
-    return dateref
+-- | Getting 'ZonedDate' from the 'ZonedDate' cache.
+getDate :: DateRef -> IO ZonedDate
+getDate (DateRef ref) = do
+    newEt <- epochTime
+    cache <- readIORef ref
+    let oldEt = unixTime cache
+    if oldEt == newEt then
+        return $ zonedDate cache
+    else do
+        newCache <- newDate newEt
+        !_ <- atomicModifyIORef ref (\_ -> (newCache, ()))
+        return $ zonedDate newCache
 
-date :: DateRef -> IO ()
-date dateref@(DateRef !ref) = do
-    !tmstr <- formatDate
-    x <- atomicModifyIORef ref (\_ -> (tmstr, ()))
-    -- atomicModifyIORef is prone to leak spaces.
-    x `seq` return ()
-    threadDelay 1000000
-    date dateref
+newDate :: EpochTime -> IO DateCache
+newDate et = DateCache et . format <$> toZonedTime et
+  where
+    toZonedTime = utcToLocalZonedTime . toUTC
+    toUTC = posixSecondsToUTCTime . realToFrac
+    format = BS.pack . formatTime defaultTimeLocale "%d/%b/%Y:%T %z"
 
-formatDate :: IO ByteString
-formatDate = do
-    tm <- getZonedTime
-    let !str = formatTime defaultTimeLocale "%d/%b/%Y:%T %z" tm
-        !tmstr = str `deepseq` BS.pack str
-    return tmstr
+-- | Initializing the 'ZonedDate' cache.
+dateInit :: IO DateRef
+dateInit = DateRef <$> (epochTime >>= newDate >>= newIORef)
diff --git a/Network/Wai/Logger/Format.hs b/Network/Wai/Logger/Format.hs
--- a/Network/Wai/Logger/Format.hs
+++ b/Network/Wai/Logger/Format.hs
@@ -1,10 +1,16 @@
 {-# LANGUAGE OverloadedStrings #-}
 
-module Network.Wai.Logger.Format (apacheFormat) where
+module Network.Wai.Logger.Format (
+    apacheFormat
+  , apacheFormatBuilder
+  ) where
 
+import Blaze.ByteString.Builder
+import Blaze.ByteString.Builder.Char8
 import Data.ByteString.Char8 ()
 import Data.CaseInsensitive
 import Data.Maybe
+import Data.Monoid
 import Network.HTTP.Types
 import Network.Wai
 import Network.Wai.Logger.Date
@@ -38,3 +44,30 @@
 
 lookupRequestField' :: CI Ascii -> Request -> Ascii
 lookupRequestField' k req = fromMaybe "" . lookup k $ requestHeaders req
+
+-- | Apache style log format with 'Builder'. This is experimental.
+apacheFormatBuilder :: ZonedDate -> Request -> Status -> Maybe Integer -> Builder
+apacheFormatBuilder tmstr req status msize =
+      st addr
+  +++ bs " - - ["
+  +++ bs tmstr
+  +++ bs "] \""
+  +++ bs (requestMethod req)
+  +++ bs " "
+  +++ bs (rawPathInfo req)
+  +++ bs " "
+  +++ st (show (httpVersion req))
+  +++ bs "\" "
+  +++ st (show (statusCode status))
+  +++ bs " "
+  +++ st (maybe "-" show msize)
+  +++ bs " \""
+  +++ bs (lookupRequestField' "referer" req)
+  +++ bs "\" \""
+  +++ bs (lookupRequestField' "user-agent" req)
+  +++ bs "\"\n"
+  where
+    addr = showSockAddr (remoteHost req)
+    st = fromString
+    bs = fromByteString
+    (+++) = mappend
diff --git a/Network/Wai/Logger/IO.hs b/Network/Wai/Logger/IO.hs
--- a/Network/Wai/Logger/IO.hs
+++ b/Network/Wai/Logger/IO.hs
@@ -3,12 +3,14 @@
 
 module Network.Wai.Logger.IO (
     LogStr(..)
-  , hPutLogStr
+  , hPutLogStr, hPutBuilder, initHandle
   ) where
 
+import Blaze.ByteString.Builder
 import qualified Data.ByteString as BS
 import Data.ByteString.Internal (ByteString(..), c2w)
 import Data.List
+import Data.Maybe
 import Foreign
 import GHC.Base
 import GHC.IO.Buffer
@@ -19,6 +21,7 @@
 import GHC.IORef
 import GHC.Num
 import GHC.Real
+import System.IO
 
 -- | A date type to contain 'String' and 'ByteString'.
 data LogStr = LS !String | LB !ByteString
@@ -67,3 +70,14 @@
 copy' dst (x:xs) = do
     poke dst (c2w x)
     copy' (dst `plusPtr` 1) xs
+
+-- | Setting a proper buffering to 'Handle'.
+initHandle :: Handle -> IO ()
+initHandle hdl = hSetBuffering hdl (BlockBuffering (Just 4096))
+
+{-| The 'hPut' function directory to copy 'Builder' to the buffer.
+    The current implementation is inefficient at this moment.
+    'initHandle' must be called once beforehand if this function is used.
+-}
+hPutBuilder :: Handle -> Builder -> IO ()
+hPutBuilder hdl = BS.hPut hdl . toByteString
diff --git a/wai-logger.cabal b/wai-logger.cabal
--- a/wai-logger.cabal
+++ b/wai-logger.cabal
@@ -1,5 +1,5 @@
 Name:                   wai-logger
-Version:                0.0.0
+Version:                0.0.1
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
 License:                BSD3
@@ -24,7 +24,8 @@
   Build-Depends:        base >= 4 && < 5, wai,
                         http-types, bytestring, filepath,
                         directory, old-locale, case-insensitive,
-                        time, deepseq, unix, byteorder, network
+                        time, deepseq, unix, byteorder, network,
+                        blaze-builder
 Source-Repository head
   Type:                 git
   Location:             git://github.com/kazu-yamamoto/wai-logger.git
