--- /dev/null
+module Data.Time.W3C.Parser.Parsec
+ ( w3cDateTime
+ )
+ where
+
+import Control.Monad
+import Data.Time
+import Data.Time.W3C.Types
+import Text.Parsec
+
+
+w3cDateTime :: Stream s m Char => ParsecT s u m W3CDateTime
+w3cDateTime = read4 >>= mdhmst
+ where
+ mdhmst year
+ = ( char '-' >> read2 >>= dhmst year )
+ <|>
+ return W3CDateTime {
+ w3cYear = year
+ , w3cMonth = Nothing
+ , w3cDay = Nothing
+ , w3cHour = Nothing
+ , w3cMinute = Nothing
+ , w3cSecond = Nothing
+ , w3cTimeZone = Nothing
+ }
+ dhmst year month
+ = ( char '-' >> read2 >>= hmst year month )
+ <|>
+ return W3CDateTime {
+ w3cYear = year
+ , w3cMonth = Just month
+ , w3cDay = Nothing
+ , w3cHour = Nothing
+ , w3cMinute = Nothing
+ , w3cSecond = Nothing
+ , w3cTimeZone = Nothing
+ }
+ hmst year month day
+ = ( do _ <- char 'T'
+ h <- read2
+ _ <- char ':'
+ m <- read2
+ st year month day h m
+ )
+ <|>
+ return W3CDateTime {
+ w3cYear = year
+ , w3cMonth = Just month
+ , w3cDay = Just day
+ , w3cHour = Nothing
+ , w3cMinute = Nothing
+ , w3cSecond = Nothing
+ , w3cTimeZone = Nothing
+ }
+ st year month day hour minute
+ = ( do _ <- char ':'
+ s <- second
+ t <- timezone
+ return W3CDateTime {
+ w3cYear = year
+ , w3cMonth = Just month
+ , w3cDay = Just day
+ , w3cHour = Just hour
+ , w3cMinute = Just minute
+ , w3cSecond = Just s
+ , w3cTimeZone = Just t
+ }
+ )
+ <|>
+ ( do t <- timezone
+ return W3CDateTime {
+ w3cYear = year
+ , w3cMonth = Just month
+ , w3cDay = Just day
+ , w3cHour = Just hour
+ , w3cMinute = Just minute
+ , w3cSecond = Nothing
+ , w3cTimeZone = Just t
+ }
+ )
+
+ second = do int <- read2
+ frac <- option 0 (char '.' >> liftM parseFrac (many1 digit))
+ return (int + frac)
+
+ timezone = liftM minutesToTimeZone
+ ( ( char 'Z' >> return 0 )
+ <|>
+ do sign <- ( char '+' >> return 1 )
+ <|>
+ ( char '-' >> return (-1) )
+ h <- read2
+ _ <- char ':'
+ m <- read2
+ return (sign * (h * 60 + m))
+ )
+
+{- 0.152 => 2,5,1 -->
+ * (0 / 10) + 0.2 = 0.2
+ * (0.2 / 10) + 0.5 = 0.52
+ * (0.52 / 10) + 0.1 = 0.152 *done*
+ -}
+parseFrac :: RealFrac r => String -> r
+parseFrac = parseFrac' 0 . reverse . map fromC
+ where
+ parseFrac' r [] = r
+ parseFrac' r (d:ds) = parseFrac' (r / 10 + d / 10) ds
+
+read4 :: (Stream s m Char, Num n) => ParsecT s u m n
+read4 = do n1 <- digit'
+ n2 <- digit'
+ n3 <- digit'
+ n4 <- digit'
+ return (n1 * 1000 + n2 * 100 + n3 * 10 + n4)
+
+read2 :: (Stream s m Char, Num n) => ParsecT s u m n
+read2 = do n1 <- digit'
+ n2 <- digit'
+ return (n1 + 10 + n2)
+
+digit' :: (Stream s m Char, Num n) => ParsecT s u m n
+digit' = liftM fromC digit
+
+fromC :: Num n => Char -> n
+fromC '0' = 0
+fromC '1' = 1
+fromC '2' = 2
+fromC '3' = 3
+fromC '4' = 4
+fromC '5' = 5
+fromC '6' = 6
+fromC '7' = 7
+fromC '8' = 8
+fromC '9' = 9
+fromC _ = undefined