Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added conversion between interval and DiffTime #115

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/Database/PostgreSQL/Simple/FromField.hs
Expand Up @@ -115,7 +115,7 @@ import qualified Data.ByteString.Char8 as B
import Data.Int (Int16, Int32, Int64)
import Data.IORef (IORef, newIORef)
import Data.Ratio (Ratio)
import Data.Time ( UTCTime, ZonedTime, LocalTime, Day, TimeOfDay )
import Data.Time ( UTCTime, ZonedTime, LocalTime, Day, TimeOfDay, DiffTime )
import Data.Typeable (Typeable, typeOf)
import Data.Vector (Vector)
import Data.Vector.Mutable (IOVector)
Expand Down Expand Up @@ -416,6 +416,10 @@ instance FromField LocalTimestamp where
instance FromField Date where
fromField = ff $(inlineTypoid TI.date) "Date" parseDate

-- | interval
instance FromField DiffTime where
fromField = ff $(inlineTypoid TI.interval) "DiffTime" parseInterval

ff :: PQ.Oid -> String -> (B8.ByteString -> Either String a)
-> Field -> Maybe B8.ByteString -> Conversion a
ff compatOid hsType parse f mstr =
Expand Down
2 changes: 2 additions & 0 deletions src/Database/PostgreSQL/Simple/Time.hs
Expand Up @@ -64,13 +64,15 @@ module Database.PostgreSQL.Simple.Time
, parseUTCTimestamp
, parseZonedTimestamp
, parseLocalTimestamp
, parseInterval
, dayToBuilder
, utcTimeToBuilder
, zonedTimeToBuilder
, localTimeToBuilder
, timeOfDayToBuilder
, timeZoneToBuilder
, dateToBuilder
, diffTimeToBuilder
, utcTimestampToBuilder
, zonedTimestampToBuilder
, localTimestampToBuilder
Expand Down
38 changes: 37 additions & 1 deletion src/Database/PostgreSQL/Simple/Time/Implementation.hs
Expand Up @@ -14,8 +14,9 @@ module Database.PostgreSQL.Simple.Time.Implementation where

import Prelude hiding (take, (++))
import Blaze.ByteString.Builder(Builder, fromByteString)
import Blaze.ByteString.Builder.Char8(fromChar)
import Blaze.ByteString.Builder.Char8(fromChar, fromString)
import Blaze.Text.Int(integral)
import Text.Printf (printf)
import Control.Arrow((***))
import Control.Applicative
import Control.Monad(when)
Expand Down Expand Up @@ -85,6 +86,9 @@ parseLocalTimestamp = A.parseOnly (getLocalTimestamp <* A.endOfInput)
parseDate :: B.ByteString -> Either String Date
parseDate = A.parseOnly (getDate <* A.endOfInput)

parseInterval :: B.ByteString -> Either String DiffTime
parseInterval = A.parseOnly (getInterval <* A.endOfInput)

getUnbounded :: A.Parser a -> A.Parser (Unbounded a)
getUnbounded getFinite
= (pure NegInfinity <* A.string "-infinity")
Expand Down Expand Up @@ -163,6 +167,33 @@ getUTCTime = do
getUTCTimestamp :: A.Parser UTCTimestamp
getUTCTimestamp = getUnbounded getUTCTime

getTimeInterval :: A.Parser DiffTime
getTimeInterval = do
h <- A.decimal
_ <- A.char ':'
m <- A.decimal
_ <- A.char ':'
s <- A.decimal
subsec <- A.option 0 (A.char '.' *> (A.decimal))
return $ secondsToDiffTime (h*3600 + m*60 + s) + picosecondsToDiffTime (subsec * 100000000000)

getDayInterval :: A.Parser DiffTime
getDayInterval = do
n <- A.signed A.decimal
factor <- A.choice [ A.string " year" *> pure (12*30*86400)
, A.string " mon" *> pure ( 30*86400)
, A.string " day" *> pure ( 86400)
]
_ <- A.string "s " <|> A.string " "
return (secondsToDiffTime (n*factor))

getInterval :: A.Parser DiffTime
getInterval = do
ds <- many getDayInterval
timesign <- A.option 1 (A.char '+' *> pure 1 <|> A.char '-' *> pure (-1))
time <- getTimeInterval
return (sum ds + time*timesign)

toNum :: Num n => B.ByteString -> n
toNum = B.foldl' (\a c -> 10*a + digit c) 0
{-# INLINE toNum #-}
Expand Down Expand Up @@ -229,6 +260,11 @@ localTimestampToBuilder = unboundedToBuilder localTimeToBuilder
dateToBuilder :: Date -> Builder
dateToBuilder = unboundedToBuilder dayToBuilder

-- Using printf here because Blaze.ByteString.Builder.double will emit
-- in scientific notation, which Postgres doesn't like.
diffTimeToBuilder :: DiffTime -> Builder
diffTimeToBuilder = fromString . printf "%f S" . (fromRational :: Rational -> Double) . toRational

showSeconds :: Pico -> Builder
showSeconds xyz
| yz == 0 = pad2 x
Expand Down
1 change: 1 addition & 0 deletions src/Database/PostgreSQL/Simple/Time/Internal.hs
Expand Up @@ -19,6 +19,7 @@ module Database.PostgreSQL.Simple.Time.Internal
, getZonedTimestamp
, getUTCTime
, getUTCTimestamp
, getInterval
) where

import Database.PostgreSQL.Simple.Time.Implementation
6 changes: 5 additions & 1 deletion src/Database/PostgreSQL/Simple/ToField.hs
Expand Up @@ -30,7 +30,7 @@ import Data.ByteString (ByteString)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.List (intersperse)
import Data.Monoid (mappend)
import Data.Time (Day, TimeOfDay, LocalTime, UTCTime, ZonedTime)
import Data.Time (Day, TimeOfDay, LocalTime, UTCTime, ZonedTime, DiffTime)
import Data.Typeable (Typeable)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import {-# SOURCE #-} Database.PostgreSQL.Simple.ToRow
Expand Down Expand Up @@ -261,6 +261,10 @@ instance ToField Date where
toField = Plain . inQuotes . dateToBuilder
{-# INLINE toField #-}

instance ToField DiffTime where
toField = Plain . inQuotes . diffTimeToBuilder
{-# INLINE toField #-}

instance (ToField a) => ToField (PGArray a) where
toField xs = Many $
Plain (fromByteString "ARRAY[") :
Expand Down