How to specify a custom DateOnly format with CsvReader?

197 Views Asked by At

I need to read a CSV file using CsvReader, however I have a custom date format (yyyyMMdd) which by default can't be converted to DateOnly. How can I specify this custom date format? Is that may possible using some annotation?

This is the code I currently have, it fails with

FormatException: String '20230817' was not recognized as a valid DateOnly.

class Foo
{
    public string Title { get; set; } = null!;
    public DateOnly Date { get; set; }
}

var sb = new StringBuilder();
sb.Append(@"Title,Date");
sb.AppendLine();
sb.Append(@"hello world,20230817");
sb.AppendLine();


using var stringReader = new StringReader(sb.ToString());
using var csvReader = new CsvReader(stringReader, CultureInfo.InvariantCulture);

int lineIndex = 0;

while(csvReader.Read())
{
    if(lineIndex == 0)
    {
        csvReader.ReadHeader();
    } else
    {
        var foo = csvReader.GetRecord<Foo>();
    }

    lineIndex++;
}
2

There are 2 best solutions below

0
Izanagi On

Based on your example you can try something like this, since you have to specify the exact format you provide

StringBuilder sb = new StringBuilder();
sb.Append(@"Title,Date");
sb.AppendLine();
sb.Append(@"hello world,20230817");
sb.AppendLine();
using var stringReader = new StringReader(sb.ToString());

using var csvReader = new CsvReader(stringReader, CultureInfo.InvariantCulture);

int lineIndex = 0;
while (csvReader.Read())
{
    if (lineIndex == 0)
    {
        csvReader.ReadHeader();
    }
    else
    {
        var foo = new Foo() { Title = csvReader.GetField<string>(0), Date = DateOnly.ParseExact(csvReader.GetField<string>(1), "yyyyMMdd") };
    }
    lineIndex++;
}
0
David Specht On

As Rand Random commented, you have two ways to add the formatting.

You can simply add the Format annotation

class Foo
{
    public string Title { get; set; } = null!;
    
    [Format("yyyyMMdd")]
    public DateOnly Date { get; set; }
}

Or you can set all DateOnly values to use the format with TypeConverterOptionsCache

var sb = new StringBuilder();
sb.AppendLine(@"Title,Date");
sb.AppendLine(@"hello world,20230817");

using var stringReader = new StringReader(sb.ToString());
using var csvReader = new CsvReader(stringReader, CultureInfo.InvariantCulture);

var options = new TypeConverterOptions { Formats = new[] { "yyyyMMdd" } };
csvReader.Context.TypeConverterOptionsCache.AddOptions<DateOnly>(options);

if (csvReader.Read())
{
    csvReader.ReadHeader();

    while (csvReader.Read())
    {
        var foo = csvReader.GetRecord<Foo>();
    }
}