    {-# LINE 1 "DB/HSQL/Type/Time.hsc" #-}
    {-# LANGUAGE CPP,ForeignFunctionInterface #-}
    {-# LINE 2 "DB/HSQL/Type/Time.hsc" #-}
    {-| `SqlBind' instance for `ClockTime'.
    -}
    module DB.HSQL.Type.Time() where

    import Control.Monad(mplus)
    import System.IO.Unsafe(unsafePerformIO)
    import System.Time(ClockTime(..),CalendarTime(..)
                      ,getClockTime,toCalendarTime,toUTCTime)
    import Text.ParserCombinators.ReadP(ReadP,char,skipSpaces,readP_to_S)
    import Text.Read.Lex(readDecP)
    import Foreign(Ptr,allocaBytes,pokeByteOff)
    import Foreign.C.Types(CTime(CTime),CInt)

    import DB.HSQL.Type
        (SqlType(SqlTimeTZ,SqlTime,SqlDate,SqlDateTimeTZ,SqlDateTime
                ,SqlTimeStamp,SqlText))
    import Database.HSQL.Types(SqlBind(..))

    {-# LINE 21 "DB/HSQL/Type/Time.hsc" #-}

    -- |
    instance SqlBind ClockTime where
        fromSqlValue SqlTimeTZ s = f_read getTimeTZ s
    	where getTimeTZ :: ReadP ClockTime
    	      getTimeTZ = do
    		(hour, minutes, seconds) <- readHMS
    		(char '.' >> readDecP) `mplus` (return 0)
    		tz <- parseTZ
    		return (mkClockTime 1970 1 1 hour minutes seconds (tz*3600))
        fromSqlValue SqlTime s = f_read getTime s
    	where getTime :: ReadP ClockTime
    	      getTime = do
    		(hour, minutes, seconds) <- readHMS
    		return (mkClockTime 1970 1 1 hour minutes seconds currTZ)
        fromSqlValue SqlDate s = f_read getDate s
    	where getDate :: ReadP ClockTime
    	      getDate = do
    		(year, month, day) <- readYMD
    		return (mkClockTime year month day 0 0 0 currTZ)
        fromSqlValue SqlDateTimeTZ s = f_read getDateTimeTZ s
    	where getDateTimeTZ :: ReadP ClockTime
    	      getDateTimeTZ = do
    	        (year, month, day, hour, minutes, seconds) <- readDateTime
    		char '.' >> readDecP -- ) `mplus` (return 0)
                    tz <- parseTZ
    		return (mkClockTime year month day
                                        hour minutes seconds
                                        (tz*3600))
        -- The only driver which seems to report the type as SqlTimeStamp seems
        -- to be the MySQL driver. MySQL (at least 4.1) uses the same format for
        -- datetime and timestamp columns.
        -- Allow SqlText to support SQLite, which reports everything as SqlText
        fromSqlValue t s
            | t == SqlDateTime || t == SqlTimeStamp || t == SqlText =
                f_read getDateTime s
                    where getDateTime :: ReadP ClockTime
    		      getDateTime = do
    			(year, month, day, hour, minutes, seconds) <-
                                readDateTime
    			return (mkClockTime year month day
                                                hour minutes seconds
                                                currTZ)
        fromSqlValue _ _ = Nothing

        toSqlValue ct =
            '\'' : (shows (ctYear t) . score .
                    shows (ctMonth t) . score .
                    shows (ctDay t) . space .
                    shows (ctHour t) . colon .
                    shows (ctMin t) . colon .
                    shows (ctSec t)) "'"
            where t = toUTCTime ct
                  score = showChar '-'
                  space = showChar ' '
                  colon = showChar ':'

    -- |
    mkClockTime :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> ClockTime
    mkClockTime year mon mday hour min sec tz =
        unsafePerformIO $ do
          allocaBytes (44) $ \p_tm -> do
    {-# LINE 84 "DB/HSQL/Type/Time.hsc" #-}
    	((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p_tm	(fromIntegral sec  :: CInt)
    {-# LINE 85 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p_tm	(fromIntegral min  :: CInt)
    {-# LINE 86 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p_tm	(fromIntegral hour :: CInt)
    {-# LINE 87 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) p_tm	(fromIntegral mday :: CInt)
    {-# LINE 88 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) p_tm	(fromIntegral (mon-1) :: CInt)
    {-# LINE 89 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 20)) p_tm	(fromIntegral (year-1900) :: CInt)
    {-# LINE 90 "DB/HSQL/Type/Time.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) p_tm	(-1 :: CInt)
    {-# LINE 91 "DB/HSQL/Type/Time.hsc" #-}
    	t <- mktime p_tm
            let t'=

    {-# LINE 94 "DB/HSQL/Type/Time.hsc" #-}
                    fromEnum t

    {-# LINE 98 "DB/HSQL/Type/Time.hsc" #-}
            return (TOD (fromIntegral t' + fromIntegral (tz-currTZ)) 0)

    foreign import ccall unsafe
      mktime :: Ptr () -> IO CTime

    -- |
    {-# NOINLINE currTZ #-}
    currTZ :: Int
    currTZ =
        ctTZ (unsafePerformIO (getClockTime >>= toCalendarTime)) -- Hack

    -- |
    parseTZ :: ReadP Int
    parseTZ =
        (char '+' >> readDecP) `mplus` (char '-' >> fmap negate readDecP)

    -- |
    f_read :: ReadP a -> String -> Maybe a
    f_read f s = case readP_to_S f s of
                   [(x,_)] -> Just x

    -- |
    readHMS :: ReadP (Int, Int, Int)
    readHMS = do
      hour  <- readDecP
      char ':'
      minutes <- readDecP
      char ':'
      seconds <- readDecP
      return (hour, minutes, seconds)

    -- |
    readYMD :: ReadP (Int, Int, Int)
    readYMD = do
      year  <- readDecP
      char '-'
      month <- readDecP
      char '-'
      day   <- readDecP
      return (year, month, day)

    -- |
    readDateTime :: ReadP (Int, Int, Int, Int, Int, Int)
    readDateTime = do
      (year, month, day) <- readYMD
      skipSpaces
      (hour, minutes, seconds) <- readHMS
      return (year, month, day, hour, minutes, seconds)