使用 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