使用 postgresql-simple 将 Postgres 间隔转换为 Haskell NominalTimeDiff
Converting Postgres interval to Haskell NominalTimeDiff with postgresql-simple
我(认为我)需要 FromField and ToField instances for NominalDiffTime,以便与具有 interval
.
类型列的 Postgres table 交互
我找到了 interval TypeInfo,并且正在弄清楚如何与 TypeInfo
交互,但希望有更简单的方法吗?
首先,有理由不提供这样的实例。 NominalDiffTime
并不代表 interval
的所有值。例如,2 days
不同于 48 hours
。特别是,1 year
不能用天来表示。
这是 NominalDiffTime
的一个 FromField
实例,它在超过一个小时的时间间隔内失败(不过 25:00:00 是可以的)。
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
我(认为我)需要 FromField and ToField instances for NominalDiffTime,以便与具有 interval
.
我找到了 interval TypeInfo,并且正在弄清楚如何与 TypeInfo
交互,但希望有更简单的方法吗?
首先,有理由不提供这样的实例。 NominalDiffTime
并不代表 interval
的所有值。例如,2 days
不同于 48 hours
。特别是,1 year
不能用天来表示。
这是 NominalDiffTime
的一个 FromField
实例,它在超过一个小时的时间间隔内失败(不过 25:00:00 是可以的)。
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