自定义DateTime转换器返回null?

时间:2017-10-12 08:06:49

标签: c# datetime csvhelper

我有一个具有DateTime类型属性的模型。在这个属性中,我希望在写入csv文件时以及从csv文件中读取时,将秒和微秒包含在字符串中,然后使用CsvHelper。

所以我在这里是通过扩展 DefaultTypeConverter

来实现解决方案的方法
public class CsvDateTimeConverter : DefaultTypeConverter
{
    private const string DateStringFormat = "MM/dd/yyyy HH:mm:ss.fff";

    public override object ConvertFromString(TypeConverterOptions options, string text)
    {
        if (string.IsNullOrEmpty(text)) return null;

        return Convert.ToDateTime(text);
    }

    public override string ConvertToString(TypeConverterOptions options, object value)
    {
        if (value == null) return "";

        var dateTime = (DateTime) value;

        return dateTime.ToString(DateStringFormat);
    }
}

模型看起来像这样

public class MyModel
{
    // ..... removed other properties
    public DateTime MyDateTime {get; set};
}

CsvClassMapper看起来像这样

public sealed class CsvMap : CsvClassMap<MyModel>
{
    public CsvMap()
    {
        Map(m => m.MyDateTime).TypeConverter<CsvDateTimeConverter>();
    }
}

我将班级地图注册到了读者和作家。但问题是:

我可以使用转换器成功写入csv文件,但是当我尝试从csv文件读取时,它可以读取其他属性但是为DateTime属性返回null。

那么......我错过了什么?

编辑:

如果有帮助:

这是从csv文件中读取的代码:

using (TextReader reader = new StreamReader(filePath))
{
     var csv = new CsvReader(reader);
     csv.Configuration.RegisterClassMap<CsvMap>();

     csv.Configuration.Encoding = Encoding.UTF8;

     return csv.GetRecords<MyModel>().ToList();
 }

3 个答案:

答案 0 :(得分:4)

您无需指定自定义类型转换器。这是美国式的DateTime格式,添加了毫秒数。您所需要的只是指定正确的文化,并可能指定要使用的格式。

一种选择是将Configuration.CultureInfo属性设置为美国文化:

reader.Configuration.CultureInfo = CultureInfo.GetCultureInfo("en-US");

以下代码将生成并读取美国日期,无毫秒:

        using (var file = new StreamWriter("test.csv"))
        {
            var writer = new CsvWriter(file);
            writer.Configuration.CultureInfo = CultureInfo.GetCultureInfo("en-US");
            writer.WriteRecords(items);
        }

        using (var file = new StreamReader("test.csv"))
        {
            var reader= new CsvReader(file);
            reader.Configuration.CultureInfo = CultureInfo.GetCultureInfo("en-US");
            var models=reader.GetRecords<MyModel>().ToArray();
            Console.WriteLine(models[0]);                
        }

您可以通过类地图中的TypeConverterOptions方法为字段指定不同的格式:

public sealed class CsvMap : CsvHelper.Configuration.CsvClassMap<MyModel>
{
    public CsvMap()
    {
        Map(m => m.Date).TypeConverterOption("MM/dd/yyyy HH:mm:ss.fff");
        Map(m => m.ID);
    }
}

以下代码只添加了类映射,将生成美国日期,以毫秒为单位:

        using (var file = new StreamWriter("test.csv"))
        {
            var writer = new CsvWriter(file);
            writer.Configuration.CultureInfo = CultureInfo.GetCultureInfo("en-US");
            writer.Configuration.RegisterClassMap<CsvMap>();
            writer.WriteRecords(items);
        }

        using (var file = new StreamReader("test.csv"))
        {
            var reader= new CsvReader(file);
            reader.Configuration.CultureInfo = CultureInfo.GetCultureInfo("en-US");
            reader.Configuration.RegisterClassMap<CsvMap>();                
            var models=reader.GetRecords<MyModel>().ToArray();
            Console.WriteLine(models[0]);                
        }

Date,ID
10/12/2017 11:56:11.016,1
10/11/2017 11:56:11.021,2

如果您不想为整个文件设置文化,也可以将CultureInfo指定为TypeConverterOption:

    public CsvMap()
    {
        Map(m => m.Date).TypeConverterOption("MM/dd/yyyy HH:mm:ss.fff")
                        .TypeConverterOption(CultureInfo.GetCultureInfo("en-US"));
        Map(m => m.ID);
    }

注意

CsvHelper最近发布了一个重大更新(3.0)(如本周)。上周不在场!目前的版本是3.2.0。

在此版本中,CsvClassMap变为CsvMap,TypeConverterOptions方法成为具有返回MapMember的方法的对象:

    public CsvMap()
    {
        string format="MM/dd/yyyy HH:mm:ss.fff";
        var enUS=CultureInfo.GetCultureInfo("en-US");

        Map(m => m.Date).TypeConverterOption.Format(format)
                        .TypeConverterOption.CultureInfo(enUS);
        Map(m => m.ID);
    }

仍然没有Type Converters的文档,更不用说TypeConverterOptions了。我找到了this Github issue中的方法,该方法应作为文档。

另一种选择是检查the source code本身。

答案 1 :(得分:0)

public override object ConvertFromString(TypeConverterOptions options, string text)
{
    if (string.IsNullOrEmpty(text)) return null;

    return Convert.ToDateTime(text);
}

您可能在这里错过了特殊格式。我是DateTime.TryConvert(...)的粉丝 - 我不喜欢Convert.XXXX。是否有理由使用特定类型的转换方法?

答案 2 :(得分:-1)

此方法

summary_score <- as.numeric(summary_score) * 8

有一个重载,它采用您必须在此处指定的格式。试试这样。

enter image description here

修改

在ConvertFromString方法中添加:

Convert.ToDateTime(text);