使用CsvHelper保存含NodaTime LocalDateTime的对象到CSV遇问题求助
解决CsvHelper导出NodaTime LocalDateTime为ISO格式字符串的问题
问题核心在于CsvHelper默认会序列化对象的所有公共属性,导致LocalDateTime被拆分为Year、Month、Day等多列。你之前的转换器无效,一是因为转成DateTime后仍可能被CsvHelper默认拆分,二是未将转换器注册到CsvHelper上下文使其生效。以下是两种可行解决方案:
方案一:自定义字符串转换器并全局注册
直接将LocalDateTime转换为目标ISO格式字符串,跳过中间转DateTime的步骤:
1. 实现字符串转换器
public class LocalDateTimeConverter : ValueConverter<LocalDateTime, string> { public LocalDateTimeConverter() : base( // 序列化:转为ISO格式字符串 localDateTime => localDateTime.ToString("yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture), // 反序列化:从字符串解析回LocalDateTime str => LocalDateTime.Parse(str, CultureInfo.InvariantCulture)) { } }
2. 在导出方法中注册转换器
修改SaveAsCSV方法,将转换器添加到CsvHelper的类型转换器缓存:
public void SaveAsCSV<T>(List<T> records, string path) { using var writer = new StreamWriter(path); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); // 注册LocalDateTime类型转换器 csv.Context.TypeConverterCache.AddConverter<LocalDateTime>(new LocalDateTimeConverter()); csv.WriteRecords(records); }
方案二:使用ClassMap精准配置(推荐)
通过类映射针对特定DTO字段定制规则,灵活度更高:
1. 创建AccountDTO的映射类
public class AccountDTOMap : ClassMap<AccountDTO> { public AccountDTOMap() { // 映射Name字段 Map(m => m.Name); // 直接配置CreatedDate的序列化逻辑 Map(m => m.CreatedDate) .ConvertUsing(row => row.CreatedDate.ToString("yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture)); // 也可以复用方案一的转换器: // Map(m => m.CreatedDate).TypeConverter<LocalDateTimeConverter>(); } }
2. 在导出方法中注册映射
public void SaveAsCSV<T>(List<T> records, string path) { using var writer = new StreamWriter(path); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); // 注册AccountDTO的映射规则 csv.Context.RegisterClassMap<AccountDTOMap>(); csv.WriteRecords(records); }
两种方案都能让CreatedDate字段导出为2008-10-31T17:04:32格式的字符串,符合预期需求。
内容的提问来源于stack exchange,提问作者Valeriy Kutsar
相关产品推荐
相关产品推荐

