C# 使用OpenXMLSDK从xlsx读取日期

C# 使用OpenXMLSDK从xlsx读取日期,c#,date,datetime,openxml,openxml-sdk,C#,Date,Datetime,Openxml,Openxml Sdk,我在其中一个单元格的xlsx文件中有一个格式为“4/5/2011”(月/日/年)的日期。我正在尝试解析文件并将这些数据加载到一些类中 到目前为止,我解析单元格的部分如下所示: string cellValue = cell.InnerText; if (cell.DataType != null) { switch (cell.DataType.Value) { case CellValues.SharedString: // get st

我在其中一个单元格的xlsx文件中有一个格式为“4/5/2011”(月/日/年)的日期。我正在尝试解析文件并将这些数据加载到一些类中

到目前为止,我解析单元格的部分如下所示:

string cellValue = cell.InnerText;
if (cell.DataType != null)
{
    switch (cell.DataType.Value)
    {
        case CellValues.SharedString:
            // get string from shared string table
            cellValue = this.GetStringFromSharedStringTable(int.Parse(cellValue));
            break;
    }
}
我希望日期是cell.DataType。事实是,当解析日期为“4/5/2011”的单元格时,cell.DataType的值为null,单元格的值为“40638”,并且它不是共享字符串表的索引。(我以前也试过,但结果是一个例外。)

有什么想法吗?
谢谢

我也遇到了同样的问题-切换到ePlus


请注意,它具有LGPL许可证。因此,如果您需要代码库不受GPL问题的影响,只需按原样使用库,您的原始代码库许可证是安全的。

Open XML将日期存储为1900年1月1日起的天数。好吧,跳过不正确的1900年2月29日作为有效日期。您应该能够找到算法来帮助您计算正确的值。我相信一些开发人员使用
DateTime.FromOADate()
作为帮助

另外,默认情况下,
单元格
类的
数据类型
属性为Number。所以如果它是空的,它是一个数字,在我们的例子中包括日期


仅当存储的日期早于历元(本例中为1900年1月1日)时,才能转到共享字符串表。在这种情况下,Cell类的CellValue保存共享字符串表的索引。

您可以使用DateTime.FromOADate(41690)

添加我的2便士值。 我正在处理一个模板,所以我知道一个给定的单元格应该是一个日期时间。 因此,我在这个方法中使用了一个字符串参数excelDateTime,其中包含单元格值,它通常是一个OADate数字,如“42540.04166664”

我的问题是,最终用户在德国,因为这是一个网站,我们将Thread.CurrentThread.CurrentCulture和Thread.CurrentThread.CurrentUICulture设置为“DE DE”。当您调用
double.TryParse
时,它使用区域性来解析数字。所以这一行:
double.TryParse(“42540.0416666664”,out-oaDate)
确实有效,但它返回
4254004166664
,因为在德国,点是一个组分隔符
DateTime.FromOADate
然后失败,因为该数字超出范围()

这使我想到:

  • 无论用户机器上的区域设置如何,OpenXML文档都包含以默认区域设置格式化的数字(在任何情况下都是US?不变量?,以点作为十进制分隔符)。我已经搜索过了,但是没有找到这个的规格
  • 当对一个可能的OADate字符串执行
    double.TryParse
    时,我们应该使用
    double.TryParse(excelDateTimeAsString,NumberStyles.Any,CultureInfo.InvariantCulture,out-oaDateAsDouble))
    。我使用的是CultureInfo.InvariantCulture,但应该是第1点,我不确定

  • 每个单元格有2个属性r(CellReference)和s(StyleIndex)

    数字的样式索引为2,日期的样式索引为3

    日期为ODate,您可以将其转换为字符串格式


    value=DateTime.FromOADate(double.Parse(value)).ToSortDateString()

    似乎没有为日期设置cell.DataType

    方法是查看单元格是否有StyleIndex,它是文档中单元格格式数组的索引

    然后使用cellFormat.NumberFormatId查看这是否是日期数据类型

    下面是一些代码:

        public class ExcelCellWithType
        {
            public string Value { get; set; }
            public UInt32Value ExcelCellFormat { get; set; }
            public bool IsDateTimeType { get; set; }
        }  
    
        public class ExcelDocumentData
        {
            public ExcelXmlStatus Status { get; set; }
            public IList<Sheet> Sheets { get; set; }
            public IList<ExcelSheetData> SheetData { get; set; }
    
            public ExcelDocumentData()
            {
                Status = new ExcelXmlStatus();
                Sheets = new List<Sheet>();
                SheetData = new List<ExcelSheetData>();
            }
        } 
    
        ...
    
        public ExcelDocumentData ReadSpreadSheetDocument(SpreadsheetDocument mySpreadsheet, ExcelDocumentData data)
        {
            var workbookPart = mySpreadsheet.WorkbookPart;
    
            data.Sheets = workbookPart.Workbook.Descendants<Sheet>().ToList();
    
            foreach (var sheet in data.Sheets)
            {
                var sheetData = new ExcelSheetData { SheetName = sheet.Name };
                var workSheet = ((WorksheetPart)workbookPart.GetPartById(sheet.Id)).Worksheet;
    
                sheetData.ColumnConfigurations = workSheet.Descendants<Columns>().FirstOrDefault();
                var rows = workSheet.Elements<SheetData>().First().Elements<Row>().ToList();
                if (rows.Count > 1)
                {
                    foreach (var row in rows)
                    {
                        var dataRow = new List<ExcelCellWithType>();
    
                        var cellEnumerator = GetExcelCellEnumerator(row);
                        while (cellEnumerator.MoveNext())
                        {
                            var cell = cellEnumerator.Current;
                            var cellWithType = ReadExcelCell(cell, workbookPart);
                            dataRow.Add(cellWithType);
                        }
    
                        sheetData.DataRows.Add(dataRow);
                    }
                }
                data.SheetData.Add(sheetData);
            }
    
            return data;
        }
    
        ...
    
        private ExcelCellWithType ReadExcelCell(Cell cell, WorkbookPart workbookPart)
        {
            var cellValue = cell.CellValue;
            var text = (cellValue == null) ? cell.InnerText : cellValue.Text;
            if (cell.DataType?.Value == CellValues.SharedString)
            {
                text = workbookPart.SharedStringTablePart.SharedStringTable
                    .Elements<SharedStringItem>().ElementAt(
                        Convert.ToInt32(cell.CellValue.Text)).InnerText;
            }
    
            var cellText = (text ?? string.Empty).Trim();
    
            var cellWithType = new ExcelCellWithType();
    
            if (cell.StyleIndex != null)
            {
                var cellFormat = workbookPart.WorkbookStylesPart.Stylesheet.CellFormats.ChildElements[
                    int.Parse(cell.StyleIndex.InnerText)] as CellFormat;
    
                if (cellFormat != null)
                {
                    cellWithType.ExcelCellFormat = cellFormat.NumberFormatId;
    
                    var dateFormat = GetDateTimeFormat(cellFormat.NumberFormatId);
                    if (!string.IsNullOrEmpty(dateFormat))
                    {
                        cellWithType.IsDateTimeType = true;
    
                        if (!string.IsNullOrEmpty(cellText))
                        {
                           if (double.TryParse(cellText, out var cellDouble))
                            {
                                var theDate = DateTime.FromOADate(cellDouble);
                                cellText = theDate.ToString(dateFormat);
                            }
                        }
                    }
                }
            }
    
            cellWithType.Value = cellText;
    
            return cellWithType;
        }
    
        //// https://msdn.microsoft.com/en-GB/library/documentformat.openxml.spreadsheet.numberingformat(v=office.14).aspx
        private readonly Dictionary<uint, string> DateFormatDictionary = new Dictionary<uint, string>()
        {
            [14] = "dd/MM/yyyy",
            [15] = "d-MMM-yy",
            [16] = "d-MMM",
            [17] = "MMM-yy",
            [18] = "h:mm AM/PM",
            [19] = "h:mm:ss AM/PM",
            [20] = "h:mm",
            [21] = "h:mm:ss",
            [22] = "M/d/yy h:mm",
            [30] = "M/d/yy",
            [34] = "yyyy-MM-dd",
            [45] = "mm:ss",
            [46] = "[h]:mm:ss",
            [47] = "mmss.0",
            [51] = "MM-dd",
            [52] = "yyyy-MM-dd",
            [53] = "yyyy-MM-dd",
            [55] = "yyyy-MM-dd",
            [56] = "yyyy-MM-dd",
            [58] = "MM-dd",
            [165] = "M/d/yy",
            [166] = "dd MMMM yyyy",
            [167] = "dd/MM/yyyy",
            [168] = "dd/MM/yy",
            [169] = "d.M.yy",
            [170] = "yyyy-MM-dd",
            [171] = "dd MMMM yyyy",
            [172] = "d MMMM yyyy",
            [173] = "M/d",
            [174] = "M/d/yy",
            [175] = "MM/dd/yy",
            [176] = "d-MMM",
            [177] = "d-MMM-yy",
            [178] = "dd-MMM-yy",
            [179] = "MMM-yy",
            [180] = "MMMM-yy",
            [181] = "MMMM d, yyyy",
            [182] = "M/d/yy hh:mm t",
            [183] = "M/d/y HH:mm",
            [184] = "MMM",
            [185] = "MMM-dd",
            [186] = "M/d/yyyy",
            [187] = "d-MMM-yyyy"
        };
    
        private string GetDateTimeFormat(UInt32Value numberFormatId)
        {
            return DateFormatDictionary.ContainsKey(numberFormatId) ? DateFormatDictionary[numberFormatId] : string.Empty;
        }
    
    公共类ExcelCellWithType
    {
    公共字符串值{get;set;}
    公共UINT32值ExcelCellFormat{get;set;}
    公共bool IsDateTimeType{get;set;}
    }  
    公共类ExcelDocumentData
    {
    公共ExcelXmlStatus状态{get;set;}
    公共IList表{get;set;}
    公共IList SheetData{get;set;}
    公共文档数据()
    {
    状态=新的ExcelXmlStatus();
    图纸=新列表();
    SheetData=新列表();
    }
    } 
    ...
    公共Excel文档数据读取电子表格文档(电子表格文档mySpreadsheet,Excel文档数据)
    {
    var workbookPart=mySpreadsheet.workbookPart;
    data.Sheets=workbookPart.Workbook.subjects().ToList();
    foreach(数据表中的var表)
    {
    var sheetData=new ExcelSheetData{SheetName=sheet.Name};
    var工作表=((WorksheetPart)workbookPart.GetPartById(sheet.Id)).workSheet;
    sheetData.ColumnConfigurations=workSheet.subjects().FirstOrDefault();
    变量行=工作表.Elements().First().Elements().ToList();
    如果(rows.Count>1)
    {
    foreach(行中的变量行)
    {
    var dataRow=新列表();
    var cellEnumerator=GetExcelCellEnumerator(行);
    while(cellEnumerator.MoveNext())
    {
    var cell=cellEnumerator.Current;
    var cellWithType=ReadExcelCell(单元格,工作簿部件);
    添加(cellWithType);
    }
    sheetData.DataRows.Add(dataRow);
    }
    }
    data.SheetData.Add(SheetData);
    }
    返回数据;
    }
    ...
    私有ExcelCellWithType ReadExcelCell(单元格单元格,WorkbookPart WorkbookPart)
    {
    var cellValue=cell.cellValue;
    var text=(cellValue==null)?cell.InnerText:cellValue.text;
    if(cell.DataType?.Value==CellValues.SharedString)
    {
    text=workbookPart.SharedStringTablePart.SharedStringTable
    .Elements().ElementAt(
    Convert.ToInt32(cell.CellValue.Text)).InnerText;
    }
    var cellText=(text??string.Empty).Trim();
    var cellWithType=新的ExcelCellWithType();
    if(cell.StyleIndex!=null)
    {
    塞尔弗
    
        public class ExcelCellWithType
        {
            public string Value { get; set; }
            public UInt32Value ExcelCellFormat { get; set; }
            public bool IsDateTimeType { get; set; }
        }  
    
        public class ExcelDocumentData
        {
            public ExcelXmlStatus Status { get; set; }
            public IList<Sheet> Sheets { get; set; }
            public IList<ExcelSheetData> SheetData { get; set; }
    
            public ExcelDocumentData()
            {
                Status = new ExcelXmlStatus();
                Sheets = new List<Sheet>();
                SheetData = new List<ExcelSheetData>();
            }
        } 
    
        ...
    
        public ExcelDocumentData ReadSpreadSheetDocument(SpreadsheetDocument mySpreadsheet, ExcelDocumentData data)
        {
            var workbookPart = mySpreadsheet.WorkbookPart;
    
            data.Sheets = workbookPart.Workbook.Descendants<Sheet>().ToList();
    
            foreach (var sheet in data.Sheets)
            {
                var sheetData = new ExcelSheetData { SheetName = sheet.Name };
                var workSheet = ((WorksheetPart)workbookPart.GetPartById(sheet.Id)).Worksheet;
    
                sheetData.ColumnConfigurations = workSheet.Descendants<Columns>().FirstOrDefault();
                var rows = workSheet.Elements<SheetData>().First().Elements<Row>().ToList();
                if (rows.Count > 1)
                {
                    foreach (var row in rows)
                    {
                        var dataRow = new List<ExcelCellWithType>();
    
                        var cellEnumerator = GetExcelCellEnumerator(row);
                        while (cellEnumerator.MoveNext())
                        {
                            var cell = cellEnumerator.Current;
                            var cellWithType = ReadExcelCell(cell, workbookPart);
                            dataRow.Add(cellWithType);
                        }
    
                        sheetData.DataRows.Add(dataRow);
                    }
                }
                data.SheetData.Add(sheetData);
            }
    
            return data;
        }
    
        ...
    
        private ExcelCellWithType ReadExcelCell(Cell cell, WorkbookPart workbookPart)
        {
            var cellValue = cell.CellValue;
            var text = (cellValue == null) ? cell.InnerText : cellValue.Text;
            if (cell.DataType?.Value == CellValues.SharedString)
            {
                text = workbookPart.SharedStringTablePart.SharedStringTable
                    .Elements<SharedStringItem>().ElementAt(
                        Convert.ToInt32(cell.CellValue.Text)).InnerText;
            }
    
            var cellText = (text ?? string.Empty).Trim();
    
            var cellWithType = new ExcelCellWithType();
    
            if (cell.StyleIndex != null)
            {
                var cellFormat = workbookPart.WorkbookStylesPart.Stylesheet.CellFormats.ChildElements[
                    int.Parse(cell.StyleIndex.InnerText)] as CellFormat;
    
                if (cellFormat != null)
                {
                    cellWithType.ExcelCellFormat = cellFormat.NumberFormatId;
    
                    var dateFormat = GetDateTimeFormat(cellFormat.NumberFormatId);
                    if (!string.IsNullOrEmpty(dateFormat))
                    {
                        cellWithType.IsDateTimeType = true;
    
                        if (!string.IsNullOrEmpty(cellText))
                        {
                           if (double.TryParse(cellText, out var cellDouble))
                            {
                                var theDate = DateTime.FromOADate(cellDouble);
                                cellText = theDate.ToString(dateFormat);
                            }
                        }
                    }
                }
            }
    
            cellWithType.Value = cellText;
    
            return cellWithType;
        }
    
        //// https://msdn.microsoft.com/en-GB/library/documentformat.openxml.spreadsheet.numberingformat(v=office.14).aspx
        private readonly Dictionary<uint, string> DateFormatDictionary = new Dictionary<uint, string>()
        {
            [14] = "dd/MM/yyyy",
            [15] = "d-MMM-yy",
            [16] = "d-MMM",
            [17] = "MMM-yy",
            [18] = "h:mm AM/PM",
            [19] = "h:mm:ss AM/PM",
            [20] = "h:mm",
            [21] = "h:mm:ss",
            [22] = "M/d/yy h:mm",
            [30] = "M/d/yy",
            [34] = "yyyy-MM-dd",
            [45] = "mm:ss",
            [46] = "[h]:mm:ss",
            [47] = "mmss.0",
            [51] = "MM-dd",
            [52] = "yyyy-MM-dd",
            [53] = "yyyy-MM-dd",
            [55] = "yyyy-MM-dd",
            [56] = "yyyy-MM-dd",
            [58] = "MM-dd",
            [165] = "M/d/yy",
            [166] = "dd MMMM yyyy",
            [167] = "dd/MM/yyyy",
            [168] = "dd/MM/yy",
            [169] = "d.M.yy",
            [170] = "yyyy-MM-dd",
            [171] = "dd MMMM yyyy",
            [172] = "d MMMM yyyy",
            [173] = "M/d",
            [174] = "M/d/yy",
            [175] = "MM/dd/yy",
            [176] = "d-MMM",
            [177] = "d-MMM-yy",
            [178] = "dd-MMM-yy",
            [179] = "MMM-yy",
            [180] = "MMMM-yy",
            [181] = "MMMM d, yyyy",
            [182] = "M/d/yy hh:mm t",
            [183] = "M/d/y HH:mm",
            [184] = "MMM",
            [185] = "MMM-dd",
            [186] = "M/d/yyyy",
            [187] = "d-MMM-yyyy"
        };
    
        private string GetDateTimeFormat(UInt32Value numberFormatId)
        {
            return DateFormatDictionary.ContainsKey(numberFormatId) ? DateFormatDictionary[numberFormatId] : string.Empty;
        }
    
        private static object Convert(this DocumentFormat.OpenXml.Spreadsheet.CellValues value, string content)
        {
            switch (value)
            {
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.Boolean:
                    if (content.Length < 2)
                    {
                        return content?.ToUpperInvariant() == "T" || content == "1";
                    }
                    return System.Convert.ToBoolean(content);
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.Date:
                    if (double.TryParse(content, out double result))
                    {
                        return System.DateTime.FromOADate(result);
                    }
                    return null;
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.Number:
                    return System.Convert.ToDecimal(content);
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.Error:
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.String:
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.InlineString:
                case DocumentFormat.OpenXml.Spreadsheet.CellValues.SharedString:
                default:
                    return content;
            }
        }