JoshClose / CsvHelper

Library to help reading and writing CSV files

Home Page:http://joshclose.github.io/CsvHelper/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to set datetime format for reading csv data

rupesh-kachhi opened this issue · comments

Problem-
I am trying to read this type of data from CSV-
DATE,grain
1/1/1992,grain
2/1/1992,grain

here date is in the format dd/MM/yyyy.

here is the necessary code -
//To read

var records = csv.GetRecords().ToList();

//to write

csvOutput.Context.RegisterClassMap();
// Write the header record.
csvOutput.WriteHeader();
csvOutput.NextRecord();
// Write the updated data records.
csvOutput.WriteRecords(records);

// Classes used
public class CsvRecord
{
public string Grain { get; set; }
[Name("DATE")]
public DateTime Date { get; set; }
}
public class CsvRecordMap : ClassMap
{
public CsvRecordMap()
{
Map(m => m.Grain);
Map(m => m.Date).TypeConverterOption.Format("yyyy/MM/dd");
}
}

After execution everything is working fine
after writecsv, I am getting date format as "yyyy/dd/MM"

if we add one record like this
13/1/1992,grain
it will give error taking default format as MM/dd/yyyy

If you are using CultureInfo.InvariantCulture, the default date format is MM/dd/yyyy. (Which I think is silly, since the majority of countries have dd/MM/yyyy as their default).

So you need to either use a CultureInfo that uses dd/MM/yyyy for your CsvReader

using (var csv = new CsvReader(reader, new CultureInfo("en-IN")))

Or use another ClassMap<CsvRecord> for your CsvReader that sets the correct format.

Map(m => m.Date).TypeConverterOption.Format("dd/MM/yyyy");

Thank you for your fast response.
But I don't want to use another class map also I was not able to parse the string to date. I was getting this error -
System.FormatException: 'String '13/1/1992' was not recognized as a valid DateTime.'
so I tried with the format "d/M/yyyy" and it worked but the mapping format was different.
So I discovered an alternative way to do the same using Custom Type Converter. and without much code change.
Here is some code snippet -

[TypeConverter(typeof(CustomDateConverter))]
public DateTime Date { get; set; }

// This is CustomDateConverter class

public class CustomDateConverter : DefaultTypeConverter

{

 public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)

 {

     string[] dateFormats = { "dd/MM/yyyy", "d/M/yyyy"};

     foreach (var format in dateFormats)
     {
         if (DateTime.TryParseExact(text, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate))
         {
             return parsedDate;
         }
     }

     throw new FormatException($"Unable to parse date: {text}");
 }

}

used this and no other code changes.

I just remembered. There is another way to do it.

var options = new TypeConverterOptions { Formats = new[] { "dd/MM/yyyy", "d/M/yyyy" } };
csvReader.Context.TypeConverterOptionsCache.AddOptions<DateTime>(options);