从OpenXml Excel文件中读取日期

bro*_*var 9 xml vb.net excel openxml .net-2.0

我正在尝试使用SharpZipLib从.xlsx文件中读取数据以解压缩(在内存中)并读取内部xml文件.一切都很好,但识别日期 - 它们以julean格式存储,我需要以某种方式识别数字是日期还是只是数字.在另一个主题(不幸的是它死了,我需要快速回答)我从Mark Ba​​ker那里了解了一些东西,但它仍然不够......

"Excel将日期存储为浮动值...整数部分是自19/1年1月1日以来的天数(或1/1/1904,具体取决于使用的日历),小数部分是一天的比例(即时间部分)......由于1900年被认为是闰年,因此稍微变得尴尬.

区分数据和数字的唯一方法是数字格式掩码.如果您可以读取格式掩码,则可以使用它来将值标识为日期而不是数字...然后从基准日期计算日期值/格式."

"但是日期的属性"s"是否始终具有"1"的值?我知道它定义了样式,但也许?;)"

s属性引用styles.xml中的样式xf条目,并且日期并不总是条目1 ...这取决于工作簿中使用了多少不同的样式.样式xf又引用数字格式掩码.要识别包含日期的单元格,您需要执行样式xf - >数字格式查找,然后确定该数字格式掩码是否是日期/时间数字格式掩码(而不是例如百分比或会计数字格式掩码)

"还有一个问题 - 我现在正在查看style.xml的内容,在我看到的元素中,我看到的元素如下:"<xf numFmtId ="14"... applyNumberFormat ="1"/>","<xf numFmtId = "1"... applyNumberFormat ="1"/>"等,但没有<numFmts>部分...是否有"标准"格式?或者我只是遗漏了什么?"

有人可以帮帮我吗?提前致谢.

Mar*_*ker 12

您应该在style.xml顶部附近的某处找到numFmts部分,作为styleSheet元素的一部分

<?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>
Run Code Online (Sandbox Code Playgroud)

编辑

我一直在仔细检查我的xlsx阅读器代码(自从我深入研究该库的这一部分以来已经有很长一段时间了); 并且有内置格式.小于164的数字格式代码(numFmtId)是"内置"的.

我的清单不完整:

0 = 'General';
1 = '0';
2 = '0.00';
3 = '#,##0';
4 = '#,##0.00';
5 = '$#,##0;\-$#,##0';
6 = '$#,##0;[Red]\-$#,##0';
7 = '$#,##0.00;\-$#,##0.00';
8 = '$#,##0.00;[Red]\-$#,##0.00';
9 = '0%';
10 = '0.00%';
11 = '0.00E+00';
12 = '# ?/?';
13 = '# ??/??';
14 = 'mm-dd-yy';
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';

37 = '#,##0 ;(#,##0)';
38 = '#,##0 ;[Red](#,##0)';
39 = '#,##0.00;(#,##0.00)';
40 = '#,##0.00;[Red](#,##0.00)';

44 = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)';
45 = 'mm:ss';
46 = '[h]:mm:ss';
47 = 'mmss.0';
48 = '##0.0E+0';
49 = '@';

27 = '[$-404]e/m/d';
30 = 'm/d/yy';
36 = '[$-404]e/m/d';
50 = '[$-404]e/m/d';
57 = '[$-404]e/m/d';

59 = 't0';
60 = 't0.00';
61 = 't#,##0';
62 = 't#,##0.00';
67 = 't0%';
68 = 't0.00%';
69 = 't# ?/?';
70 = 't# ??/??';
Run Code Online (Sandbox Code Playgroud)


小智 8

细胞可能有样式.这些是在styleSheet中索引cellXfs的uint.每个cellXfs项都包含一组属性.最重要的是NumberFormatID.如果其值落在14-22范围内,则为"标准"日期.如果它落在165-180的范围内,则它是"格式化"的日期,并且具有相应的NumberingFormat属性.

标准日期

[x:cr ="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:cr ="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++;
     }
Run Code Online (Sandbox Code Playgroud)


小智 5

我建议 numFmtId="14" 应该被视为“Windows 短日期格式”,因为在澳大利亚,这种格式将日期显示为“dd/mm/yy”,而不是“mm/dd/yy”。