2011-01-11 392 views
8

我试图从SharpZipLib中读取.xlsx文件中的数据以解压缩(在内存中)并读取内部xml文件。一切都很好,但承认日期 - 他们存储在julean格式,我需要以某种方式识别,如果一个数字是一个日期或只有一个数字。在另一个主题(不幸的是它死了,我需要快速回答)我知道一些事情从马克贝克,但它仍然是不够的...从OpenXml Excel文件中读取日期

“Excel存储日期作为一个浮点值...整数部分是自1/1/1900(或1/1/1904,取决于使用哪个日历)以来的天数,小数部分是一天中的比例(即时间部分)......稍微有些尴尬1900年被认为是一个闰年

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

“但不属性‘S’的日期始终的值‘1’,我知道它定义的风格,但也许;?)”

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

“还有一个问题 - 我现在在看style.xml的内容和我看到类似元素的部分:” < XF numFmtId =“14” ...... applyNumberFormat =“1”/>” “< xf numFmtId =”1“... applyNumberFormat =”1“/ >”等,但没有<numFmts> section ...有没有任何“标准”格式?或者我只是缺少什么?

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

+1

这里的日期格式ID列表http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.NumberingFormat(v=office.14).aspx的[ – 2014-05-30 11:13:33

+0

可能重复什么指示Office Open XML Cell包含日期/时间值?](http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value) – MikeTeeVee 2015-02-16 23:35:37

回答

10

你应该找到附近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> 

编辑

我已经仔细检查我的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# ??/??'; 
+0

这就是numFmts应该被保留的地方。工作簿是否使用Excel本身生成?如果您在MS Excel中打开有问题的文件,它是否将单元格值识别为日期? – 2011-01-11 09:00:11

8

细胞可能具有的风格。这些都是在styleSheet中索引cellXfs的索引。每个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: [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 = “米/ 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++; 
    } 
4

我建议numFmtId =“14”应该被认为是“Windows短日期格式”在澳大利亚这种格式会显示一个日期,“DD/MM/YY”,而不是“毫米/ DD/YY”。

0

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

您首先抓住“s”或StyleIndex。注意在下面的数字原始格式(40667)日期:

<row r="1"> 
    <c r="A1" s="1"> 
    <v>40667</v> 
    </c> 
</row> 

的“S”属性在细胞中的节点指向styles.xml节点的从零开始的数组从0开始。这是关键的定位日期格式(如果有)映射到原始数字日期数据。你看,S = 1,指向下面的单元格格式Excel工作簿的styles.xml区第2 XF节点:

<cellXfs count="2"> 
    <xf numFmtId="0" ... /> 
    <xf numFmtId="14" ... /> 
    </cellXfs> 

在你看到numFmtId =“14”值,第二个节点。这是numberFormatID。它告诉你,这是确定你的日期编号应该用什么来表示的id。但是这个数字指向日期格式的两个可能的位置。如果它的数量在14-22的范围内,那么它是一种内置式的日期。如果它的外部范围(可能)是由Excel文件所有者添加的自定义日期格式。你不知道,直到你检查两个地方。

在第一种情况下,如果其值为14-22,则需要将其映射到每个excel文件具有(mm-dd-yy等)的预构建日期格式之一。您可以在OpenXML SDK中找到该表。这里是那些映射到内置的日期格式的numFmtId的样本....

14 mm-dd-yy 
15 d-mmm-yy 
16 d-mmm 
17 mmm-yy 
18 h:mm AM/PM 

在这一点上,你知道它的日期,什么格式,它在呈现。如果它不是一个这些值,它可能是一个自定义数字。您现在必须再次搜索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,你发现它的自定义日期格式。因此,为了抓住所有这些疯狂的日期格式,定制和内置,最好的办法是将一系列可接受的“格式”保存为字符串,找到您的formatCode,然后查看它是否与您的代码中的某个可接受的格式匹配。

祝你好运!