使用postgresql simple将Postgres interval转换为Haskell NominalTimeDiff

使用postgresql simple将Postgres interval转换为Haskell NominalTimeDiff,postgresql,haskell,time,Postgresql,Haskell,Time,我(认为我)需要和实例,以便与具有interval类型的列的Postgres表接口 我已经找到了TypeInfo,正在研究如何与TypeInfo交互,但希望有一种更简单的方法?首先,有理由不提供这样的实例NominalDiffTime不能合理地表示interval的所有值。例如,2天不同于48小时。特别是,1年不能用天来表示 这里有一个FromField实例,用于NominalDiffTime,当组件的间隔大于一小时时(比如25:00:00是可以的),该实例会失败 实例FromField Nom

我(认为我)需要和实例,以便与具有
interval
类型的列的Postgres表接口


我已经找到了TypeInfo,正在研究如何与
TypeInfo
交互,但希望有一种更简单的方法?

首先,有理由不提供这样的实例
NominalDiffTime
不能合理地表示
interval
的所有值。例如,
2天
不同于
48小时
。特别是,
1年
不能用天来表示

这里有一个
FromField
实例,用于
NominalDiffTime
,当组件的间隔大于一小时时(比如25:00:00是可以的),该实例会失败

实例FromField NominalDiffTime其中
fromField mdat=
如果typeOid f/=typeid间隔
然后返回错误f“”
其他情况下的mdat
Nothing->returnError UnexpectedNull f“”
Just dat->case parseOnly(nominalDiffTime returnError ConversionFailed f msg
右t->返回t
nominalDiffTime::解析器nominalDiffTime
nominalDiffTime=do

(h、m、s)我现在看到一个
ToField
实例存在,只是缺少了
FromField
。是的,这就是为什么postgresql simple不包含一个开箱即用的
FromField
实例,用于
NominalDiffTime
。另一方面,实现某种Haskell类型可以忠实地报告发送了postgresql的interval类型。这方面的有限实例可能有用,但我没有考虑太多。(另外,
2天
48小时
的原因不同,因为在日常生活中使用的每个时区中,并非所有的日子都是24小时长的。)。(客户可能需要当地时间)大多数例外情况是夏令时轮班23小时或25小时,但不是全部;请参阅IANA tz数据库以了解这些奇怪的情况。)
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