2017-10-12 60 views
2

我有一個具有DateTime類型屬性的模型。從這個屬性中,當寫入csv文件和從csv文件讀取CsvHelper時,我希望在字符串中包含秒和微秒。自定義DateTime coverter返回null?

所以,我在這裏是如何通過擴展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>(); 
    } 
} 

我註冊了m班給讀者和作者。但問題是:

我可以使用轉換器成功寫入csv文件,但是當我嘗試從csv文件讀取時,它可以讀取其他屬性,但返回null作爲DateTime屬性。

那麼..我錯過了什麼?

編輯:

,如果有幫助:

這是代碼從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(); 
} 
+0

用DateTime.ParseExact()替換Convert.ToDateTime(text)並使用格式:「MM/dd/yyyy HH:mm:ss.fff」 – jdweng

+0

什麼是自定義DateTime轉換器?這不會轉換任何東西,它只是一個簡單的調用'Convert.ToDateTime(text)'。這將使用當前語言環境的格式 –

+0

'CsvDateTimeConverter'中的代碼似乎正常工作(如果我直接調用它)。也許這是轉換器的註冊問題?請參閱[C#小提琴](https://dotnetfiddle.net/ypQ5Nt) –

回答

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本身。

+0

就像一個魅力.. Merci beaucoup – ash

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

    return Convert.ToDateTime(text); 
} 

你可能會在這裏失去了你的特殊格式。我是DateTime.TryConvert(...)的粉絲 - 不喜歡Convert.XXXX。是否有理由使用該類型轉換方法?

+0

否'Convert.'方法接受格式字符串。這是由每種類型的「ParseExact」方法提供的 –

-1

這種方法

Convert.ToDateTime(text); 

具有過載,它接受它,你將不得不在這裏指定的格式。像那樣試試。

enter image description here

編輯:

在你ConvertFromString方法補充一點:

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

    DateTimeFormatInfo info = new DateTimeFormatInfo() { FullDateTimePattern = DateStringFormat }; 

    return Convert.ToDateTime(text, info); 
} 
+0

仔細查看圖像。這是爲'CultureInfo',而不是一個格式字符串 –

+0

是不是你在DateTimeFormatInfo中定義DatePattern並且不會被給定的方法使用? – Rob

+0

@Rob:你可能會認爲這個問題明顯不符合你的意思,但是'private const string DateStringFormat ='MM/dd/yyyy HH:mm:ss.fff';'一般而言,我不確定爲什麼要在您想要的日期格式時創建或查找「CultureInfo」。在這裏清晰地顯示日期格式(如本例中)意味着格式應該是什麼也沒有問題 - 不需要查找文化來找出他們使用的格式等。 – Chris