2011-01-11 156 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,然後查看它是否與您的代碼中的某個可接受的格式匹配。

祝你好運!