diff --git a/ArTimestampWiper.hs b/ArTimestampWiper.hs
new file mode 100644
--- /dev/null
+++ b/ArTimestampWiper.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module ArTimestampWiper where
+
+import           Control.Applicative
+import           Control.Monad
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BS8
+import           Data.Char
+import           System.IO
+
+
+-- | Removes the time stamps of all files in the .a file.
+arFileWipeTimeStamps :: FilePath -> IO ()
+arFileWipeTimeStamps path = withBinaryFile path ReadWriteMode $ \h -> do
+
+  -- We iterate through the archive stepping from one file header to the next,
+  -- setting the time stamp field to zero.
+  -- The size field tells us where the next header is.
+  -- See: http://en.wikipedia.org/wiki/Ar_%28Unix%29.
+
+  archiveSize <- hFileSize h
+
+  let go entryOffset | entryOffset == archiveSize = return () -- done, at end
+                     | entryOffset >  archiveSize = die "Archive truncated"
+                     -- Headers are aligned to even bytes
+                     | odd entryOffset            = go (entryOffset + 1)
+                     | otherwise = do
+
+        -- Sanity check
+        magic <- goto 58 >> BS.hGet h 2
+        when (magic /= "\x60\x0a") $ die "Bad ar magic"
+
+        -- Get size (to find following file)
+        size <- goto 48 >> parseSize . BS8.unpack <$> BS.hGet h 10
+
+        -- Wipe time stamp
+        goto 16 >> BS.hPut h "0           " -- 12 chars
+
+        -- Seek to next file at header + file size
+        go (entryOffset + 60 + size)
+
+        where
+          goto pos = hSeek h AbsoluteSeek (entryOffset + pos)
+
+          parseSize x = case reads x of
+            [(s, r)] | all isSpace r -> s
+            _                        -> die "Malformed header"
+
+          die msg = error $ "arFileWipeTimeStamps: " ++ path ++ ": "
+                            ++ msg ++ " at offset " ++ show entryOffset
+
+  go 8 -- 8 == size of global header, before first file header
+
+
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import           System.Environment (getArgs)
+
+import           ArTimestampWiper
+
+main :: IO ()
+main = do
+  args <- getArgs
+  case args of
+    [file] -> arFileWipeTimeStamps file
+    _      -> error "Usage: ar-timestamp-wiper [file.a]"
+
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/ar-timestamp-wiper.cabal b/ar-timestamp-wiper.cabal
new file mode 100644
--- /dev/null
+++ b/ar-timestamp-wiper.cabal
@@ -0,0 +1,45 @@
+name:          ar-timestamp-wiper
+version:       0.1.0
+license:       MIT
+copyright:     2013 Niklas Hambüchen <mail@nh2.me>
+author:        Niklas Hambüchen <mail@nh2.me>
+maintainer:    Niklas Hambüchen <mail@nh2.me>
+category:      Application
+build-type:    Simple
+stability:     experimental
+tested-with:   GHC==7.6.3
+cabal-version: >= 1.10
+homepage:      https://github.com/nh2/ar-timestamp-wiper
+bug-reports:   https://github.com/nh2/ar-timestamp-wiper/issues
+synopsis:      Wipes time stamps from .a files (like ar -D)
+description:
+  This application takes an archive (.a) file as created by the Unix ar tool,
+  and sets all time stamps in it to zero.
+  .
+  These time stamps make ar generate different output for same input every time,
+  which is problematic if you want to know if the contents actually changed
+  as compared to the last time you created the archive (e.g. in build tools
+  to avoid unnecessary linking).
+  .
+  Recent versions of GNU binutils and BSD ar af the -D flag for deterministic
+  mode that creates the archive with all time stamps set to zero.
+  However, these versions of ar are not wide spread yet, and this tool
+  can help with that.
+
+source-repository head
+  type:      git
+  location:  git://github.com/nh2/ar-timestamp-wiper.git
+
+
+library
+  default-language: Haskell2010
+  exposed-modules:  ArTimestampWiper
+  build-depends:    base < 5, bytestring >= 0.9
+  ghc-options:      -Wall
+
+
+executable ar-timestamp-wiper
+  default-language: Haskell2010
+  main-is:          Main.hs
+  build-depends:    base < 5, bytestring >= 0.9
+  ghc-options:      -Wall
