diff --git a/Data/UnixTime.hs b/Data/UnixTime.hs
new file mode 100644
--- /dev/null
+++ b/Data/UnixTime.hs
@@ -0,0 +1,30 @@
+module Data.UnixTime (
+  -- * Data structure
+    UnixTime(..)
+  -- * Getting time
+  , getUnixTime
+  -- * Parsing and formatting time
+  , parseUnixTime
+  , parseUnixTimeGMT
+  , formatUnixTime
+  , formatUnixTimeGMT
+  , Format
+  , webDateFormat
+  , mailDateFormat
+  -- * Difference time
+  , UnixDiffTime
+  , diffUnixTime
+  , addUnixDiffTime
+  , secondsToUnixDiffTime
+  , microSecondsToUnixDiffTime
+  -- * Translating time
+  , fromEpochTime
+  , toEpochTime
+  , fromClockTime
+  , toClockTime
+  ) where
+
+import Data.UnixTime.Conv
+import Data.UnixTime.Sys
+import Data.UnixTime.Types
+import Data.UnixTime.Diff
diff --git a/Data/UnixTime/Conv.hs b/Data/UnixTime/Conv.hs
new file mode 100644
--- /dev/null
+++ b/Data/UnixTime/Conv.hs
@@ -0,0 +1,121 @@
+{-# LANGUAGE OverloadedStrings, ForeignFunctionInterface #-}
+
+module Data.UnixTime.Conv (
+    formatUnixTime, formatUnixTimeGMT
+  , parseUnixTime, parseUnixTimeGMT
+  , webDateFormat, mailDateFormat
+  , fromEpochTime, toEpochTime
+  , fromClockTime, toClockTime
+  ) where
+
+import Data.ByteString
+import Data.ByteString.Unsafe
+import Data.UnixTime.Types
+import Foreign.C.String
+import Foreign.C.Types
+import Foreign.Marshal.Alloc
+import System.IO.Unsafe (unsafePerformIO)
+import System.Posix.Types (EpochTime)
+import System.Time (ClockTime(..))
+
+foreign import ccall unsafe "c_parse_unix_time"
+        c_parse_unix_time :: CString -> CString -> IO CTime
+
+foreign import ccall unsafe "c_parse_unix_time_gmt"
+        c_parse_unix_time_gmt :: CString -> CString -> IO CTime
+
+foreign import ccall unsafe "c_format_unix_time"
+        c_format_unix_time :: CString -> CTime -> CString -> CInt -> IO ()
+
+foreign import ccall unsafe "c_format_unix_time_gmt"
+        c_format_unix_time_gmt :: CString -> CTime -> CString -> CInt -> IO ()
+
+----------------------------------------------------------------
+
+{-| Parsing 'ByteString' to 'UnixTime' interpreting as localtime.
+    Zone in 'Format' (%Z or %z) would be ignored.
+    This is a wrapper for strptime_l().
+-}
+parseUnixTime :: Format -> ByteString -> UnixTime
+parseUnixTime fmt str = unsafePerformIO $
+    useAsCString fmt $ \cfmt ->
+        useAsCString str $ \cstr -> do
+            sec <- c_parse_unix_time cfmt cstr
+            return $ UnixTime sec 0
+
+{-| Parsing 'ByteString' to 'UnixTime' interpreting as GMT.
+    Zone in 'Format' (%Z or %z) would be ignored.
+    This is a wrapper for strptime_l().
+-}
+parseUnixTimeGMT :: Format -> ByteString -> UnixTime
+parseUnixTimeGMT fmt str = unsafePerformIO $
+    useAsCString fmt $ \cfmt ->
+        useAsCString str $ \cstr -> do
+            sec <- c_parse_unix_time_gmt cfmt cstr
+            return $ UnixTime sec 0
+
+----------------------------------------------------------------
+
+{-| Formatting 'UnixTime' to 'ByteString' in local time.
+    This is a wrapper for strftime_l().
+-}
+formatUnixTime :: Format -> UnixTime -> ByteString
+formatUnixTime fmt (UnixTime sec _) = unsafePerformIO $
+    useAsCString fmt $ \cfmt -> do
+        let siz = 256 -- FIXME
+        ptr <- mallocBytes siz
+        c_format_unix_time cfmt sec ptr (fromIntegral siz)
+        unsafePackMallocCString ptr
+
+{-| Formatting 'UnixTime' to 'ByteString' in GMT.
+    This is a wrapper for strftime_l().
+-}
+formatUnixTimeGMT :: Format -> UnixTime -> ByteString
+formatUnixTimeGMT fmt (UnixTime sec _) = unsafePerformIO $
+    useAsCString fmt $ \cfmt -> do
+        let siz = 256 -- FIXME
+        ptr <- mallocBytes siz
+        c_format_unix_time_gmt cfmt sec ptr (fromIntegral siz)
+        unsafePackMallocCString ptr
+
+----------------------------------------------------------------
+
+{-| Format for web (RFC 2616).
+    This should be used with 'formatUnixTimeGMT'.
+-}
+webDateFormat :: Format
+webDateFormat = "%a, %d %b %Y %H:%M:%S GMT"
+
+{-| Format for e-mail (RFC 5322).
+    This should be used with 'formatUnixTime'.
+-}
+mailDateFormat :: Format
+mailDateFormat = "%a, %d %b %Y %H:%M:%S %z"
+
+----------------------------------------------------------------
+
+{-| From 'EpochTime' to 'UnixTime' setting 'utMicroSeconds' to 0.
+-}
+fromEpochTime :: EpochTime -> UnixTime
+fromEpochTime sec = UnixTime sec 0
+
+{-| From 'UnixTime' to 'EpochTime' ignoring 'utMicroSeconds'.
+-}
+toEpochTime :: UnixTime -> EpochTime
+toEpochTime (UnixTime sec _) = sec
+
+{-| From 'ClockTime' to 'UnixTime'.
+-}
+fromClockTime :: ClockTime -> UnixTime
+fromClockTime (TOD sec psec) = UnixTime sec' usec'
+  where
+    sec' = fromIntegral sec
+    usec' = fromIntegral $ psec `div` 1000000
+
+{-| From 'UnixTime' to 'ClockTime'.
+-}
+toClockTime :: UnixTime -> ClockTime
+toClockTime (UnixTime sec usec) = TOD sec' psec'
+  where
+    sec' = truncate (toRational sec)
+    psec' = fromIntegral $ usec * 1000000
diff --git a/Data/UnixTime/Diff.hs b/Data/UnixTime/Diff.hs
new file mode 100644
--- /dev/null
+++ b/Data/UnixTime/Diff.hs
@@ -0,0 +1,82 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Data.UnixTime.Diff (
+    diffUnixTime
+  , addUnixDiffTime
+  , secondsToUnixDiffTime
+  , microSecondsToUnixDiffTime
+  ) where
+
+import Data.UnixTime.Types
+import Data.Int
+import Foreign.C.Types
+
+----------------------------------------------------------------
+
+calc :: CTime -> Int32 -> UnixDiffTime
+calc sec usec = uncurry UnixDiffTime . ajust sec $ usec
+
+calc' :: CTime -> Int32 -> UnixDiffTime
+calc' sec usec = uncurry UnixDiffTime . slowAjust sec $ usec
+
+calcU :: CTime -> Int32 -> UnixTime
+calcU sec usec = uncurry UnixTime . ajust sec $ usec
+
+instance Num UnixDiffTime where
+	UnixDiffTime s1 u1 + UnixDiffTime s2 u2 = calc (s1+s2) (u1+u2)
+	UnixDiffTime s1 u1 - UnixDiffTime s2 u2 = calc (s1-s2) (u1-u2)
+	UnixDiffTime s1 u1 * UnixDiffTime s2 u2 = calc' (s1*s2) (u1*u2)
+	negate (UnixDiffTime s u) = UnixDiffTime (-s) (-u)
+	abs (UnixDiffTime s u) = UnixDiffTime (abs s) (abs u)
+	signum (UnixDiffTime s u)
+         | s == 0 && u == 0 = 0
+         | s > 0            = 1
+         | otherwise        = -1
+	fromInteger i = UnixDiffTime (fromInteger s) (fromInteger u)
+         where (s,u) = secondMicro i
+
+----------------------------------------------------------------
+
+-- | Calculating difference between two 'UnixTime'.
+diffUnixTime :: UnixTime -> UnixTime -> UnixDiffTime
+diffUnixTime (UnixTime s1 u1) (UnixTime s2 u2) = calc (s1-s2) (u1-u2)
+
+-- | Adding difference to 'UnixTime'.
+addUnixDiffTime :: UnixTime -> UnixDiffTime -> UnixTime
+addUnixDiffTime (UnixTime s1 u1) (UnixDiffTime s2 u2) = calcU (s1+s2) (u1+u2)
+
+-- | Creating difference from seconds.
+secondsToUnixDiffTime :: Int -> UnixDiffTime
+secondsToUnixDiffTime sec = UnixDiffTime (fromIntegral sec) 0
+
+-- | Creating difference from micro seconds.
+microSecondsToUnixDiffTime :: Int -> UnixDiffTime
+microSecondsToUnixDiffTime usec = calc (fromIntegral s) (fromIntegral u)
+  where
+    (s,u) = secondMicro usec
+
+----------------------------------------------------------------
+
+ajust :: CTime -> Int32 -> (CTime, Int32)
+ajust sec usec
+  | sec >= 0  = ajp
+  | otherwise = ajm
+  where
+    micro  = 1000000
+    mmicro = - micro
+    ajp
+     | usec >= micro  = (sec + 1, usec - micro)
+     | usec >= 0      = (sec, usec)
+     | otherwise      = (sec - 1, usec + micro)
+    ajm
+     | usec <= mmicro = (sec - 1, usec + micro)
+     | usec < 0       = (sec, usec)
+     | otherwise      = (sec + 1, usec - micro)
+
+slowAjust :: CTime -> Int32 -> (CTime, Int32)
+slowAjust sec usec = (sec + fromIntegral s, usec - u)
+  where
+    (s,u) = secondMicro u
+
+secondMicro :: Integral a => a -> (a,a)
+secondMicro usec = usec `quotRem` 1000000
diff --git a/Data/UnixTime/Sys.hsc b/Data/UnixTime/Sys.hsc
new file mode 100644
--- /dev/null
+++ b/Data/UnixTime/Sys.hsc
@@ -0,0 +1,31 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module Data.UnixTime.Sys (getUnixTime) where
+
+import Data.UnixTime.Types
+import Foreign.C.Error
+import Foreign.C.Types
+import Foreign.Marshal.Alloc
+import Foreign.Ptr
+import Foreign.Storable
+
+-- from System.Time
+
+#include <time.h>
+#include <sys/time.h>
+
+type CTimeVal = ()
+type CTimeZone = ()
+
+foreign import ccall unsafe "gettimeofday"
+    gettimeofday :: Ptr CTimeVal -> Ptr CTimeZone -> IO CInt
+
+{-| Getting 'UnixTime' from OS.
+-}
+getUnixTime :: IO UnixTime
+getUnixTime =
+  allocaBytes (#const sizeof(struct timeval)) $ \ p_timeval -> do
+    throwErrnoIfMinus1_ "getClockTime" $ gettimeofday p_timeval nullPtr
+    sec <- (#peek struct timeval,tv_sec) p_timeval
+    usec <- (#peek struct timeval,tv_usec) p_timeval
+    return $ UnixTime sec usec
diff --git a/Data/UnixTime/Types.hs b/Data/UnixTime/Types.hs
new file mode 100644
--- /dev/null
+++ b/Data/UnixTime/Types.hs
@@ -0,0 +1,20 @@
+module Data.UnixTime.Types where
+
+import Data.ByteString
+import Data.ByteString.Char8 ()
+import Data.Int
+import Foreign.C.Types
+
+-- | Data structure for Unix time.
+data UnixTime = UnixTime {
+  -- | Seconds from 1st Jan 1970
+    utSeconds :: !CTime
+  -- | Micro seconds (i.e. 10^(-6))
+  , utMicroSeconds :: !Int32
+  } deriving (Eq,Ord,Show)
+
+-- | Format of the strptime()/strftime() style.
+type Format = ByteString
+
+-- | Data structure for UnixTime diff.
+data UnixDiffTime = UnixDiffTime !CTime !Int32 deriving (Eq,Ord,Show)
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2009, IIJ Innovation Institute Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+  * Neither the name of the copyright holders nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cbits/conv.c b/cbits/conv.c
new file mode 100644
--- /dev/null
+++ b/cbits/conv.c
@@ -0,0 +1,37 @@
+#include <time.h>
+#include <locale.h>
+#include <xlocale.h>
+
+locale_t c_locale = NULL;
+
+locale_t init_locale() {
+    if (c_locale == NULL) c_locale = newlocale(LC_ALL_MASK, NULL, NULL);
+}
+
+time_t c_parse_unix_time(char *fmt, char *src) {
+    struct tm dst;
+    init_locale();
+    strptime_l(src, fmt, &dst, c_locale);
+    return mktime(&dst);
+}
+
+time_t c_parse_unix_time_gmt(char *fmt, char *src) {
+    struct tm dst;
+    init_locale();
+    strptime_l(src, fmt, &dst, c_locale);
+    return timegm(&dst);
+}
+
+void c_format_unix_time(char *fmt, time_t src, char* dst, int siz) {
+    struct tm tim;
+    init_locale();
+    localtime_r(&src, &tim);
+    strftime_l(dst, siz, fmt, &tim, c_locale);
+}
+
+void c_format_unix_time_gmt(char *fmt, time_t src, char* dst, int siz) {
+    struct tm tim;
+    init_locale();
+    gmtime_r(&src, &tim);
+    strftime_l(dst, siz, fmt, &tim, c_locale);
+}
diff --git a/unix-time.cabal b/unix-time.cabal
new file mode 100644
--- /dev/null
+++ b/unix-time.cabal
@@ -0,0 +1,28 @@
+Name:                   unix-time
+Version:                0.0.0
+Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
+Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
+License:                BSD3
+License-File:           LICENSE
+Synopsis:               Unix time parser\/formatter and utilities
+Description:            Fast parser\/formatter\/utilities for Unix time
+Category:               Data
+Cabal-Version:          >= 1.6
+Build-Type:             Simple
+Extra-Source-Files:     cbits/conv.c
+library
+  if impl(ghc >= 6.12)
+    GHC-Options:        -Wall -fno-warn-unused-do-bind
+  else
+    GHC-Options:        -Wall
+  Exposed-Modules:      Data.UnixTime
+  Other-Modules:        Data.UnixTime.Conv
+                        Data.UnixTime.Diff
+                        Data.UnixTime.Types
+                        Data.UnixTime.Sys
+  Build-Depends:        base >= 4 && < 5,bytestring, old-time
+  C-Sources:            cbits/conv.c
+
+Source-Repository head
+  Type:                 git
+  Location:             git://github.com/kazu-yamamoto/http-date
