You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:54:59