Reputation: 2329
I (think I) need FromField and ToField instances for NominalDiffTime, in order to interface with a Postgres table with a column of type interval
.
I've found the interval TypeInfo and am in the process of figuring out how to interface with TypeInfo
, but hopefully there is an easier way?
Upvotes: 1
Views: 259
Reputation: 2329
First off, there are reasons not to provide such an instance. NominalDiffTime
doesn't sensibly represent all values of interval
. For example, 2 days
is different from 48 hours
. Particularly, 1 year
can't be expressed in days.
Here's a FromField
instance for NominalDiffTime
that fails for intervals with components that are larger than an hour (something like 25:00:00 is ok, though).
instance FromField NominalDiffTime where
fromField f mdat =
if typeOid f /= typoid interval
then returnError Incompatible f ""
else case mdat of
Nothing -> returnError UnexpectedNull f ""
Just dat -> case parseOnly (nominalDiffTime <* endOfInput) dat of
Left msg -> returnError ConversionFailed f msg
Right t -> return t
nominalDiffTime :: Parser NominalDiffTime
nominalDiffTime = do
(h, m, s) <- interval
return . fromRational . toRational $ s + 60*(fromIntegral m) + 60*60*(fromIntegral h)
-- | Parse a limited postgres interval of the form [-]HHH:MM:SS.[SSSS] (no larger units than hours).
interval :: Parser (Int, Int, Pico)
interval = do
h <- signed decimal <* char ':'
m <- twoDigits <* char ':'
s <- seconds
if m < 60 && s <= 60
then return (h, m, s)
else fail "invalid interval"
-- functions below borrowed from postgresql-simple
seconds :: Parser Pico
twoDigits :: Parser Int
Upvotes: 3