OpenXML – Cell.DateType为null

我无法确定Cell何时是一个date。

日期数据类型单元

我注意到DataType是空的,所以我不能区分它是否是一个date的数字。

我正在使用下一个代码来提取单元格:

WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(worksheetId); SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>(); Row[] rows = worksheetPart.Worksheet.Descendants<Row>().ToArray(); for (int i = 0; i < rows.Length; i++) { List<Cell> cells = rows[i].Elements<Cell>().ToList(); foreach (var cell in cells) { if (cell.DataType != null && cell.DataType.Value == CellValues.Date) //this line is not hit for some reason } } } 

我错过了什么吗?

简而言之,它是空的,因为它应该是数字和datetypes。

msdn上的 OpenXML文档

对于数字和datetypes,DataType属性的值为null。 它包含用于string的值CellValues.SharedString,用于布尔值的CellValues.Boolean。

虽然有一种方法可以使用CellFormat上的NumberFormatId来区分date和数字单元格格式 。 诀窍是find什么id映射到什么格式。 您可以通过创build新的Excel文件并将单元格设置为所讨论的格式(即date)来了解要使用的格式:

在这里输入图像说明

然后使用7zip提取excel文件并查看xl / styles.xml文件:

在这里输入图像说明

在上面的图片中,您可以看到这个格式ID 14转换为短date。 有关格式的完整列表,请参阅Office Open XML格式的ECMA-376文档 (表格应该埋在第4部分的某处)。

我为最常见的formatIds创build了一个枚举:

 private enum Formats { General = 0, Number = 1, Decimal = 2, Currency = 164, Accounting = 44, DateShort = 14, DateLong = 165, Time = 166, Percentage = 10, Fraction = 12, Scientific = 11, Text = 49 } 

然后你可以创build一个帮助函数,以你想要的方式得到你的格式化值:

 private static string GetFormattedCellValue(WorkbookPart workbookPart, Cell cell) { if (cell == null) { return null; } string value = ""; if (cell.DataType == null) // number & dates { int styleIndex = (int)cell.StyleIndex.Value; CellFormat cellFormat = (CellFormat)workbookPart.WorkbookStylesPart.Stylesheet.CellFormats.ElementAt(styleIndex); uint formatId = cellFormat.NumberFormatId.Value; if (formatId == (uint)Formats.DateShort || formatId == (uint)Formats.DateLong) { double oaDate; if (double.TryParse(cell.InnerText, out oaDate)) { value = DateTime.FromOADate(oaDate).ToShortDateString(); } } else { value = cell.InnerText; } } else // Shared string or boolean { switch (cell.DataType.Value) { case CellValues.SharedString: SharedStringItem ssi = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(int.Parse(cell.CellValue.InnerText)); value = ssi.Text.Text; break; case CellValues.Boolean: value = cell.CellValue.InnerText == "0" ? "false" : "true"; break; default: value = cell.CellValue.InnerText; break; } } return value; } 

你有没有尝试cell.HasValue保证? 因为int和Datetime并不总是可以为空的,所以它取决于代码的写法。