diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Text/XML/XSD/DateTime.hs b/Text/XML/XSD/DateTime.hs
new file mode 100644
--- /dev/null
+++ b/Text/XML/XSD/DateTime.hs
@@ -0,0 +1,75 @@
+-- | XSD @dateTime@ data structure <http://www.w3.org/TR/xmlschema-2/#dateTime>
+module Text.XML.XSD.DateTime(
+                              DateTime,
+                              dateTime',
+                              dateTime
+                            ) where
+
+import Text.ParserCombinators.Parsec
+import Data.Maybe
+import Control.Monad
+
+data DateTime = DateTime Bool Int Int Int Int Int Int Int Offset
+  deriving Eq
+
+instance Show DateTime where
+  show (DateTime neg cc yy mm dd hhh mmm sss tz) =
+    join [if neg then "-" else [], showi cc, showi yy, "-", showi mm, "-", showi dd, "T", showi hhh, ":", showi mmm, ":", showi sss, show tz]
+
+-- | Parses the string into a @dateTime@ or may fail with a parse error.
+dateTime' :: String -> Either ParseError DateTime
+dateTime' = parse parseDateTime "DateTime parser"
+
+-- | Parses the string into a @dateTime@ or may fail.
+dateTime :: String -> Maybe DateTime
+dateTime = either (const Nothing) Just . dateTime'
+
+-- not exported
+
+data Offset = Offset Bool (Maybe Bool) (Maybe Int) (Maybe Int)
+  deriving Eq
+
+instance Show Offset where
+  show (Offset False Nothing Nothing Nothing) = []
+  show (Offset True Nothing Nothing Nothing) = "Z"
+  show (Offset False (Just neg) (Just hh) (Just mm)) = join [if neg then "-" else "+", showi hh, ":", showi mm]
+  show _ = error "Offset invariant not met"
+
+showi :: (Num a, Ord a) => a -> String
+showi n = (if n < 10 then ('0':) else id) (show n)
+
+examples :: [String]
+examples = ["2009-10-10T03:10:10-05:00", "2009-10-10T03:10:10+15:00", "2009-10-10T03:10:10Z", "-2009-05-10T21:08:59-05:00", "-9399-12-31T13:10:10+15:00", "-2009-10-10T03:10:10Z"]
+
+parseOffset :: GenParser Char st Offset
+parseOffset = let e = const (Offset False Nothing Nothing Nothing) `fmap` eof
+                  z = const (Offset True Nothing Nothing Nothing) `fmap` char 'Z'
+                  o = do neg <- fmap (== '-') (char '+' <|> char '-')
+                         hh <- p2imax 23
+                         char ':'
+                         mm <- p2imax 59
+                         return (Offset False (Just neg) (Just hh) (Just mm))
+              in e <|> z <|> o
+
+parseDateTime :: GenParser Char st DateTime
+parseDateTime = do neg <- isJust `fmap` optionMaybe (char '-')
+                   cc <- p2i
+                   yy <- p2i
+                   char '-'
+                   mm <- p2imax 12
+                   char '-'
+                   dd <- p2imax 31
+                   char 'T'
+                   hhh <- p2imax 23
+                   char ':'
+                   mmm <- p2imax 59
+                   char ':'
+                   sss <- p2imax 59
+                   o <- parseOffset
+                   return (DateTime neg cc yy mm dd hhh mmm sss o)
+
+p2i :: GenParser Char st Int
+p2i = liftM2 (\a b -> read [a, b]) digit digit
+
+p2imax :: Int -> GenParser Char st Int
+p2imax m = p2i >>= (\n -> if n > m then unexpected ("expecting <= " ++ show m) else return n)
diff --git a/xsd.cabal b/xsd.cabal
new file mode 100644
--- /dev/null
+++ b/xsd.cabal
@@ -0,0 +1,25 @@
+Name:                xsd
+Version:             0.1
+License:             BSD3
+License-File:        LICENSE
+Synopsis:            XML Schema data structures
+Description:         XML Schema data structures (XSD)
+Homepage:            http://code.google.com/p/data-xsd/
+Category:            XML
+Author:              Tony Morris
+Maintainer:          code@tmorris.net
+Copyright:           2009 Tony Morris
+build-type:          Simple
+cabal-version:       >= 1.2
+
+Flag small_base
+  Description:     Choose the new, split-up base package.
+
+Library
+  if flag(small_base)
+    Build-Depends: base < 4 && >= 3, parsec
+  else
+    Build-Depends: base < 3, parsec
+
+  GHC-Options:    -Wall
+  Exposed-Modules: Text.XML.XSD.DateTime
