从OpenXml Excel文件读取日期

从OpenXml Excel文件读取日期,xml,vb.net,excel,.net-2.0,openxml,Xml,Vb.net,Excel,.net 2.0,Openxml,我正在尝试使用SharpZipLib从.xlsx文件中读取数据以将其解包(在内存中)并读取内部xml文件。一切都很好,但要识别日期——它们是以朱利安格式存储的,我需要以某种方式识别一个数字是日期还是仅仅是一个数字。在另一个主题中(不幸的是它死了,我需要快速的回答),我从马克·贝克那里了解了一些事情,但这仍然不够 “Excel将日期存储为浮点值…整数部分是自1900年1月1日(或1904年1月1日,取决于所使用的日历)以来的天数,小数部分是一天的比例(即时间部分)…1900年被视为闰年,这让人觉得

我正在尝试使用SharpZipLib从.xlsx文件中读取数据以将其解包(在内存中)并读取内部xml文件。一切都很好,但要识别日期——它们是以朱利安格式存储的,我需要以某种方式识别一个数字是日期还是仅仅是一个数字。在另一个主题中(不幸的是它死了,我需要快速的回答),我从马克·贝克那里了解了一些事情,但这仍然不够

“Excel将日期存储为浮点值…整数部分是自1900年1月1日(或1904年1月1日,取决于所使用的日历)以来的天数,小数部分是一天的比例(即时间部分)…1900年被视为闰年,这让人觉得有些尴尬

唯一区别数据和数字的是数字格式掩码。如果可以读取格式掩码,可以使用该掩码将值标识为日期而不是数字…然后从基准日期计算日期值/格式。“

“但是日期的属性“s”是否总是值为“1”?我知道它定义了样式,但可能是?;)”

s属性引用了styles.xml中的一个style xf条目,对于日期,它并不总是条目1。。。这完全取决于工作簿中使用了多少种不同的样式。样式xf依次引用数字格式掩码。要标识包含日期的单元格,需要执行样式xf->numberformat查找,然后标识该numberformat掩码是否为日期/时间numberformat掩码(而不是百分比或记帐numberformat掩码)

“还有一个问题-我现在正在查看style.xml的内容,在这一节中我看到了诸如:”、“”等元素。但是没有这一节……是否有任何“标准”格式?或者我只是缺少了一些内容?


有人能帮我吗?提前感谢。

您应该在style.xml顶部附近找到numFmts部分,作为样式表元素的一部分

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
    <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <numFmts count="3">
            <numFmt numFmtId="164" formatCode="[$-414]mmmm\ yyyy;@" /> 
            <numFmt numFmtId="165" formatCode="0.000" /> 
            <numFmt numFmtId="166" formatCode="#,##0.000" /> 
        </numFmts>

单元格可能有样式。这些是在样式表中索引cellxf的单元。每个cellXfs项都包含一组属性。最重要的是数字格式。如果其值在14-22范围内,则为“标准”日期。如果它在165-180范围内,则为“格式化”日期,并具有相应的NumberingFormat属性

标准日期 [x:c r=“A2”s=“2”][x:v]38046[/x:v][x:c]

[x:xf numFmtId=“14”fontId=“0”fillId=“0”borderId=“0”xfId=“0”applyNumberFormat=“1/”(序号位置2)

格式化日期 [x:c r=“A4”s=“4”][x:v]38048[/x:v][x:c]

[x:xf numFmtId=“166”fontId=“0”fillId=“0”borderId=“0”xfId=“0”applyNumberFormat=“1/”(序号位置4)

[x:numFmt numFmtId=“166”formatCode=“m/d;”@/]

此代码提取与这些日期格式对应的样式ID列表

  private void GetDateStyles()
  {
     //
     // The only way to tell dates from numbers is by looking at the style index. 
     // This indexes cellXfs, which contains NumberFormatIds, which index NumberingFormats.
     // This method creates a list of the style indexes that pertain to dates.
     WorkbookStylesPart workbookStylesPart = (WorkbookStylesPart) UriPartDictionary["/xl/styles.xml"];
     Stylesheet styleSheet = workbookStylesPart.Stylesheet;
     CellFormats  cellFormats = styleSheet.CellFormats;

     int i = 0;
     foreach (CellFormat cellFormat in cellFormats)
     {
        uint numberFormatId = cellFormat.NumberFormatId;
        if ((numberFormatId >= 14 && numberFormatId <= 22) 
        || (numberFormatId >= 165u && numberFormatId <= 180u))
        {
           _DateStyles.Add(i.ToString());
        }
        i++;
     }
private void GetDateStyles()
{
//
//从数字中辨别日期的唯一方法是查看样式索引。
//这将为cellXfs编制索引,cellXfs包含NumberFormatds,后者索引NumberFormats。
//此方法创建和日期相关的样式索引列表。
WorkbookStylesPart WorkbookStylesPart=(WorkbookStylesPart)UriPartDictionary[“/xl/styles.xml”];
样式表样式表=工作簿样式spart.Stylesheet;
CellFormats CellFormats=样式表.CellFormats;
int i=0;
foreach(CellFormat CellFormat中的CellFormat)
{
uint numberFormatId=cellFormat.numberFormatId;

如果((numberFormatId>=14&&numberFormatId=165u&&numberFormatId我建议numFmtId=“14”应被视为“Windows短日期格式”,因为在澳大利亚,此格式将显示日期为“dd/mm/yy”,而不是“mm/dd/yy”。

有两种方法可以获取单元格的日期格式

首先抓取“s”或样式索引。请注意以下数字原始格式的日期(40667):

此时,您知道它是一个日期以及它的显示格式。如果它不是这些值之一,则可能是一个自定义数字。现在,您必须再次搜索styles.xml文件,以查找具有匹配numFmtId值的样式节点。这些节点将包含自定义日期格式,如下所示:

    <numFmts count="2">
        <numFmt numFmtId="164" formatCode="mm/yyyy;@" /> 
        <numFmt numFmtId="165" formatCode="0.000" /> 
        <numFmt numFmtId="166" formatCode="#,##0.000" /> 
    </numFmts>

请注意,如果您的numFmtId为164,您会发现它的自定义日期格式。因此,要捕获所有这些疯狂的自定义和内置日期格式,最好的办法是将一系列可接受的“格式”保持为字符串,找到您的格式代码,然后查看它是否与代码中可接受的格式之一匹配


祝你好运!

这就是NUMFMT应该保存的地方。工作簿是用Excel本身生成的吗?如果你在MS Excel中打开有问题的文件,它是否会将单元格值识别为日期?是的,并且单元格格式为日期(如果我在其中输入类似40180的数字,它也会将其转换为日期).很抱歉,我的反应太慢、太迟疑了…我已经很久没有看那一段代码了,我只是忘记了“内置”的设置。您的问题现在促使我查找列表中没有的其他字符。在我的代码的其余部分中,当我测试格式掩码是否为日期或时间格式时,我会检查格式掩码中是否存在任何ymdHis字符;但请注意颜色名称中的这些字符(例如,#,#0;[青色](#,#35; 0'))或者任何以“\u”或“0”开头的格式掩码。关于“其他”-我想它们都列在这里的“第4部分”文件中:(第2134页+)如何获取UriPartDictionary?好的。我已经知道了。_document=SpreadsheetDocument.Open(filePath,true);UriPartDictionary=BuildUriPartDictionary(\u document);未正确记录。但POI在中声明相同。ECMA中尚未正式确认。据我所知。这里有一份日期格式ID的列表,可能与Yep重复。我同意你的看法。似乎在互联网上有两个版本,一个是
<row r="1">
  <c r="A1" s="1">
    <v>40667</v>
  </c>
</row>
   <cellXfs count="2">
     <xf numFmtId="0" ... />
     <xf numFmtId="14" ... />
   </cellXfs>
14  mm-dd-yy
15  d-mmm-yy
16  d-mmm
17  mmm-yy
18  h:mm AM/PM
    <numFmts count="2">
        <numFmt numFmtId="164" formatCode="mm/yyyy;@" /> 
        <numFmt numFmtId="165" formatCode="0.000" /> 
        <numFmt numFmtId="166" formatCode="#,##0.000" /> 
    </numFmts>