Custom conversions when writing CSV files using CsvHelper

Posted on

Problem :

I’ve been doing some CSV reading and writing lately, and ran across CsvHelper which is fantastic so far. I’ve ran into one small problem; I use a custom converter when reading the files, but when I write them back out, that format is lost. My CSV format looks like this:


The fields 20150115,750 map to a single DateTime field called Start (So, 01/15/2015 7:50 AM). My class map looks like this:

public sealed class DutyMap : CsvClassMap<Duty>
    static readonly CultureInfo enUS = new CultureInfo("en-US");

    public DutyMap()
        Map(m => m.PersonId).Index(0);
        Map(m => m.DutyName).Index(1);
        Map(m => m.Start).ConvertUsing(row => ParseDate(row.GetField<String>(2), row.GetField<String>(3)));
        Map(m => m.End).ConvertUsing(row => ParseDate(row.GetField<String>(4), row.GetField<String>(5)));
        Map(m => m.DutyTime1).Index(6);
        Map(m => m.DutyTime2).Index(7);
        Map(m => m.FlightTime).Index(8);
        Map(m => m.CreditHours).Index(9);
        Map(m => m.DutyType).Index(10);

    private static DateTime ParseDate(string date, string time)
        DateTime ret;

        if (time.Length < 4)
            time = new String('0', 4 - time.Length) + time;

        if (!DateTime.TryParseExact(date + time, "yyyyMMddHHmm", enUS, DateTimeStyles.None, out ret))
            throw new FormatException(String.Format("Could not parse DateTime.  Date: {0} Time: {1}", date, time));

        return ret;

This works great, and I can now call parse an entire file like so:

var csv = new CsvReader(sr);
csv.Configuration.HasHeaderRecord = false;

Data = csv.GetRecords<Duty>().ToList();

However, when I write the file:


The file is written out like so:

67,7454-1,1/15/2015 7:50:00 AM,1/15/2015 1:40:00 PM,549,549,406,0,FPG

Looking through the documentation, I don’t see a way to specify a conversation function upon writing, only reading. The only solution I’ve found so far is to manually write each record by hand:

var csv = new CsvWriter(sw);
foreach (var item in Data)


Is there a better way to do this? Thanks!

Solution :

You can do it with a custom type converters ( Just override ConvertToString method.

public class TestConverter : DefaultTypeConverter
    public override string ConvertToString(TypeConverterOptions options, object value)
        return base.ConvertToString(options, value);

and specify converter when mapping:

Map(m => m.PersonId).Index(0).TypeConverter<TestConverter>();

If you end up here looking for a way to convert doubles in round-trip compatible format, you can use the below which uses the G17 format.

using (var writer = new StreamWriter("C:/path..."))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    csv.Context.TypeConverterOptionsCache.AddOptions<double?>(new TypeConverterOptions 
        Formats = new string[] { "G17" } 


Leave a Reply

Your email address will not be published. Required fields are marked *