使用Haskell/cassava将UTCTime转换为CSV字段



我开始学习Haskell,我尝试从SQLite文件查询数据,并将其再次转储为CSV。我有一个问题格式化UTCTime字段,以便cassava可以正确格式化它。这是我的类型:

    module History.Types
      (Visit)
      where
    import Data.ByteString as B
    import Data.Csv
    import Data.Text (Text)
    import Data.Time
    import Data.Time.Format
    import Database.SQLite.Simple.FromRow
    data Visit = Visit
      { url :: Text
      , title :: Text
      , visit_count :: Int
      , typed_count :: Int
      , last_visit_time :: UTCTime
      , visit_time :: UTCTime
      , from_visit :: Int
      }
      deriving (Show)
    instance FromRow Visit where
      fromRow = Visit <$> field
                      <*> field
                      <*> field
                      <*> field
                      <*> field
                      <*> field
                      <*> field
    instance ToField UTCTime where
      toField t = formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t
    instance ToRecord Visit where
      toRecord (Visit url
                      title
                      visit_count
                      typed_count
                      last_visit_time
                      visit_time
                      from_visit) = record [ toField visit_time
                                           , toField url
                                           , toField title
                                           , toField visit_count
                                           , toField typed_count
                                           , toField from_visit
                                           , toField last_visit_time
                                           ]

我的SQLite代码:

    {-# LANGUAGE OverloadedStrings #-}
    module History.DB
      (queryHistory)
      where
    import History.Types (Visit)
    import Data.Text (Text)
    import Database.SQLite.Simple (open, query_, close, Query)
    q :: Query
    q = "
    SELECT urls.url 
         , urls.title 
         , urls.visit_count 
         , urls.typed_count 
         , datetime(urls.last_visit_time/1000000-11644473600,'unixepoch','localtime') 
         , datetime(visits.visit_time/1000000-11644473600,'unixepoch','localtime') 
         , visits.from_visit 
    FROM urls, visits 
    WHERE urls.id = visits.id 
    ORDER BY visits.visit_time"
    queryHistory :: FilePath -> IO [Visit]
    queryHistory dbPath =
      do conn <- open dbPath
         history <- query_ conn q
         close conn
         return history

编译此代码会导致以下错误:

    src/History/Types.hs:34:15:
        Couldn't match type ‘[Char]’ with ‘ByteString’
          Expected type: Field
          Actual type: String
        In the expression:
          formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t
        In an equation for ‘toField’:
          toField t = formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t

所以很明显,我把日期类型格式化成字符串时弄得一团糟。我查看了formatTime的类型信息,并没有真正理解为什么我的String(我假设错误与日期格式字符串有关)必须是ByteString。所以我的问题是:

  1. 错误是否与时间格式化字符串有关,如果是,为什么常规字符串不起作用?
  2. 这是正确的方式来格式化日期类型写入使用cassava的CSV文件?

您的问题是toField具有a -> Field的签名。如果你看Field类型,它的定义是type Field = ByteStringformatTime的结果是String。因此,问题是您在需要ByteString的地方提供了String

由于String是一个非常常见的类型,你应该做的第一件事是检查是否已经有一个ToField String的实例可以使用。如果你看一下定义。这意味着您可以专门化toField函数,使其具有签名String -> Field,并像这样使用它:

instance ToField UTCTime where
      toField = toField . formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S"

您是否在历史记录中尝试过{-# LANGUAGE overloaddstrings #-} ?类型的文件?不确定这是否有效,但也许值得一试。

ToField必须返回一个ByteString,因为它返回一个字段,而一个字段是一个ByteString:

http://haddock.stackage.org/lts - 2.17 -/-木薯- 0.4.3.0/data csv.html # t:字段

你正确地调用了formatTime,只是formatTime返回一个String而不是一个ByteString。

可以直接使用fromString或pack进行转换。像现在这样调用formatTime并转换结果。

最新更新