使用ExcelDataReader将Excel转CSV时如何仅保留日期格式?
解决ExcelDataReader转CSV日期格式问题及CsvHelper解析报错方案
问题描述
我正在使用ExcelDataReader NuGet包将Excel文件转换为CSV,但转换后得到的是带时分秒的datetime格式(yyyy-MM-dd hh:mm:ss t),而我需要的是dd/MM/yyyy或yyyy-MM-dd的纯日期格式。后续用CsvHelper解析CSV文件为对象列表时,日期值解析报错。我尝试过判断列值是否包含AM并替换空字符串,但这并非理想方案,附上相关代码:
private static bool SaveAsCsv(string excelFilePath, string destinationCsvFilePath, string password) { System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { IExcelDataReader reader = null; //var conf = new ExcelReaderConfiguration { Password = password}; if (excelFilePath.EndsWith(".xls")) { reader = ExcelReaderFactory.CreateBinaryReader(stream); } else if (excelFilePath.EndsWith(".xlsx")) { reader = ExcelReaderFactory.CreateOpenXmlReader(stream); } if (reader == null) return false; var ds = reader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration() { UseHeaderRow = false, } }); var csvContent = string.Empty; int row_no = 0; while (row_no < ds.Tables[0].Rows.Count) { var arr = new List<string>(); for (int i = 0; i < ds.Tables[0].Columns.Count; i++) { if (ds.Tables[0].Rows[row_no][i].ToString().Contains("AM")) { ds.Tables[0].Rows[row_no][i].ToString().Replace("12:00:00 AM",""; } arr.Add(ds.Tables[0].Rows[row_no][i].ToString()!); } row_no++; csvContent += string.Join(",", arr) + "\n"; } StreamWriter csv = new StreamWriter(destinationCsvFilePath, false); csv.Write(csvContent); csv.Close(); return true; } }
方案一:Excel转CSV阶段格式化日期
直接判断单元格值的类型,对DateTime类型数据指定格式输出,替代字符串替换的方式,更精准高效。同时优化代码性能和资源管理:
private static bool SaveAsCsv(string excelFilePath, string destinationCsvFilePath, string password) { System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); var csvContentBuilder = new StringBuilder(); using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { IExcelDataReader reader = null; if (excelFilePath.EndsWith(".xls")) { reader = ExcelReaderFactory.CreateBinaryReader(stream); } else if (excelFilePath.EndsWith(".xlsx")) { reader = ExcelReaderFactory.CreateOpenXmlReader(stream); } if (reader == null) return false; var ds = reader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration() { UseHeaderRow = false, } }); var table = ds.Tables[0]; foreach (DataRow row in table.Rows) { var arr = new List<string>(); foreach (var item in row.ItemArray) { if (item is DateTime dateValue) { // 按需选择格式:yyyy-MM-dd 或 dd/MM/yyyy arr.Add(dateValue.ToString("yyyy-MM-dd")); } else { var str = item.ToString() ?? string.Empty; // 处理含逗号的字符串,用引号包裹避免CSV解析错误 if (str.Contains(",")) { arr.Add($"\"{str}\""); } else { arr.Add(str); } } } csvContentBuilder.AppendLine(string.Join(",", arr)); } } using (var csv = new StreamWriter(destinationCsvFilePath, false)) { csv.Write(csvContentBuilder.ToString()); } return true; }
关键优化点
- 用
StringBuilder替代字符串拼接,提升大文件处理性能 - 直接判断值类型为
DateTime,精准格式化,避免字符串替换的局限性 - 自动处理含逗号的字符串,用引号包裹防止CSV解析出错
- 用
using管理StreamWriter,自动释放资源,避免内存泄漏
方案二:CsvHelper解析阶段处理日期格式
如果无需修改转CSV的逻辑,可在CsvHelper解析时配置支持多种日期格式,兼容原带时分秒的格式和目标纯日期格式:
方式1:全局配置日期格式
using (var reader = new StreamReader("your.csv")) using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) { var config = csv.Configuration; // 添加所有需要支持的日期格式 config.TypeConverterOptionsCache.GetOptions<DateTime>().Formats = new[] { "yyyy-MM-dd hh:mm:ss tt", "yyyy-MM-dd", "dd/MM/yyyy" }; // 若使用可空DateTime,需同步配置 config.TypeConverterOptionsCache.GetOptions<DateTime?>().Formats = new[] { "yyyy-MM-dd hh:mm:ss tt", "yyyy-MM-dd", "dd/MM/yyyy" }; var records = csv.GetRecords<YourEntity>().ToList(); }
方式2:自定义ClassMap映射
// 实体类映射配置 public class YourEntityMap : ClassMap<YourEntity> { public YourEntityMap() { Map(m => m.DateProperty) .TypeConverterOption.Format("yyyy-MM-dd hh:mm:ss tt") .TypeConverterOption.Format("yyyy-MM-dd") .TypeConverterOption.Format("dd/MM/yyyy"); // 其他属性映射... } } // 解析时注册映射 using (var reader = new StreamReader("your.csv")) using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) { csv.Context.RegisterClassMap<YourEntityMap>(); var records = csv.GetRecords<YourEntity>().ToList(); }
说明
CsvHelper会依次尝试配置的日期格式,匹配到可解析的格式后自动转换为DateTime类型,解决解析报错问题。
内容的提问来源于stack exchange,提问作者shreyas35
相关产品推荐
相关产品推荐

