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/iso8601-time.cabal b/iso8601-time.cabal
new file mode 100644
--- /dev/null
+++ b/iso8601-time.cabal
@@ -0,0 +1,34 @@
+name:          iso8601-time
+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:      Time
+build-type:    Simple
+stability:     experimental
+tested-With:   GHC==7.6.3
+cabal-version: >= 1.8
+homepage:      https://github.com/nh2/iso8601-time
+bug-Reports:   https://github.com/nh2/iso8601-time/issues
+synopsis:      Convert to/from the ISO 8601 time format
+description:
+  Conversion functions between Haskell time types and the ISO 8601 format,
+  which is often used for printing times, e.g. JavaScript's @new Date().toISOString()@.
+  .
+  CHANGELOG
+  .
+  Version 0.1.0
+  .
+  * Initial version.
+
+source-repository head
+  type:      git
+  location:  git://github.com/nh2/iso8601-time.git
+
+
+library
+  exposed-modules: Data.Time.ISO8601
+  build-depends:   base < 5, old-locale, time
+  hs-source-dirs:  src
+  ghc-options:     -Wall
diff --git a/src/Data/Time/ISO8601.hs b/src/Data/Time/ISO8601.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Time/ISO8601.hs
@@ -0,0 +1,76 @@
+module Data.Time.ISO8601
+  ( formatISO8601
+  , formatISO8601Millis
+  , formatISO8601Micros
+  , formatISO8601Nanos
+  , formatISO8601Picos
+  , formatISO8601Javascript
+  , parseISO8601
+  ) where
+
+
+import Data.Time.Clock (UTCTime)
+import Data.Time.Format (formatTime, parseTime)
+import System.Locale (defaultTimeLocale)
+
+
+-- | Formats a time in ISO 8601, with up to 12 second decimals.
+--
+-- This is the `formatTime` format @%FT%T%Q@ == @%%Y-%m-%dT%%H:%M:%S%Q@.
+--
+-- For
+formatISO8601 :: UTCTime -> String
+formatISO8601 t = formatTime defaultTimeLocale "%FT%T%QZ" t
+
+
+-- | Pads an ISO 8601 date with trailing zeros, but lacking the trailing Z.
+formatPadded :: UTCTime -> String
+formatPadded t
+  | length str == 19 = str ++ ".000000000"
+  | otherwise        = str ++ "000000000"
+  where
+    str = formatTime defaultTimeLocale "%FT%T%Q" t
+
+
+-- | Formats a time in ISO 8601 with up to millisecond precision and trailing zeros.
+-- The format is precisely:
+--
+-- >YYYY-MM-DDTHH:mm:ss.sssZ
+formatISO8601Millis :: UTCTime -> String
+formatISO8601Millis t = take 23 (formatPadded t) ++ "Z"
+
+
+-- | Formats a time in ISO 8601 with up to microsecond precision and trailing zeros.
+-- The format is precisely:
+--
+-- >YYYY-MM-DDTHH:mm:ss.ssssssZ
+formatISO8601Micros :: UTCTime -> String
+formatISO8601Micros t = take 26 (formatPadded t) ++ "Z"
+
+
+-- | Formats a time in ISO 8601 with up to nanosecond precision and trailing zeros.
+-- The format is precisely:
+--
+-- >YYYY-MM-DDTHH:mm:ss.sssssssssZ
+formatISO8601Nanos :: UTCTime -> String
+formatISO8601Nanos t = take 29 (formatPadded t) ++ "Z"
+
+-- | Formats a time in ISO 8601 with up to picosecond precision and trailing zeros.
+-- The format is precisely:
+--
+-- >YYYY-MM-DDTHH:mm:ss.ssssssssssssZ
+formatISO8601Picos :: UTCTime -> String
+formatISO8601Picos t = take 32 (formatPadded t) ++ "Z"
+
+
+-- | Formats a time like JavaScript's @new Date().toISOString()@
+-- as specified by Mozilla: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>
+--
+-- This is an alias for `formatISO8601Millis`.
+formatISO8601Javascript :: UTCTime -> String
+formatISO8601Javascript = formatISO8601Millis
+
+
+-- | Parses an ISO 8601 string.
+parseISO8601 :: String -> Maybe UTCTime
+parseISO8601 t = parseTime defaultTimeLocale "%FT%T%QZ" t
