I'm trying to parse a csv file with data like this. I can parse with the date as a string, but haven't been able to get them in a day format. I finally got this to type check, but now I have a parse error and am hoping for some help.
2001/12/18, 281
2001/12/19, 280
2001/12/20, 276
2001/12/21, 278
Here's my code so far.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
import Data.Time
import Generics.Deriving
datadir="/home/john/.stack/test/data/"
data Sample = Sample { dateMeasure :: !Data.Time.Day
, valueMeasure :: !Int
} deriving (Generic, Show)
instance FromRecord Sample
instance FromField Data.Time.Day where
parseField = parseTimeM True defaultTimeLocale "%Y/%m/%d" . show
printRecord :: Sample -> IO ()
printRecord r = putStrLn $ show (dateMeasure r) ++ " measurement is " ++ show (valueMeasure r)
main :: IO ()
main = do
csvData <- BL.readFile $ datadir ++ "sample.csv"
case decode NoHeader csvData :: Either String (V.Vector Sample) of
Left err -> putStrLn err
Right v -> V.forM_ v $ printRecord
Here is the error I am getting
~/.stack/test/ stack exec test
parse error (Failed reading: conversion error: parseTimeM: no parse of "\"2001/12/18\"") at
2001/12/19, 280
2001/12/20, 276
2001/12/21, 278
2001/12/26, 278
2001/12/27, 278
2001/12/28, 2 (truncated)
You are using show
, which wraps the value in double quotes. parseTimeM
is receiving the value "\"2001/12/18\""
, and it doesn't know expect the quotes at the beginning and end of the string. Remove those quotes and you should be fine.
The question is pretty old, but I've just dealt with it myself, so let me post it here.
According to the manual, parseField
is a function of type:
parseField :: Field -> Parser a
In our case we want type a
to be Day
, while Field
is just a type alias
type Field = ByteString
The function that you use:
parseTimeM True defaultTimeLocale "%Y/%m/%d"
Expects a String
, not a ByteString
. So in order to make everything correct, you need to provide an adapter function ByteString -> String
.
Using show
makes it all type check, but it has the flaw that it leaves the quotation marks in the resulting string.
A better choice would be to use unpack
function that is meant to perform the conversion between the types.
So the entire code is:
import Data.ByteString.Char8 (unpack)
instance FromField Data.Time.Day where
parseField = parseTimeM True defaultTimeLocale "%Y/%m/%d" . unpack
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With