繁体   English   中英

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

[英]Convert UTCTime to CSV field with Haskell/cassava

我开始学习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的类型信息, formatTime并不太了解为什么我的String (我认为错误与日期格式字符串有关)必须是ByteString 所以我的问题是:

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

您的问题是toField具有签名toField a -> Field 如果查看Field类型,则其定义为type Field = ByteString formatTime的结果是String 因此,问题在于您提供了一个需要ByteStringString

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

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

您是否在History.Types文件中尝试过{-#LANGUAGE OverloadedStrings#-}? 不知道这是否行得通,但也许值得一试。

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

http://haddock.stackage.org/lts-2.17/cassava-0.4.3.0/Data-Csv.html#t:Field

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

您可以直接使用fromString或pack进行转换。 因此,像现在一样调用formatTime并转换结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM