Чтение дат из файлов OpenXml Excel - PullRequest
8 голосов
/ 11 января 2011

Я пытаюсь прочитать данные из файлов .xlsx, используя SharpZipLib для распаковки (в памяти) и чтения внутренних файлов xml.Все хорошо, но с распознаванием дат - они хранятся в юлианском формате, и мне нужно как-то распознать, является ли число датой или только числом.В другой теме (к сожалению, она умерла, и мне нужен быстрый ответ) Я кое-что узнал от Марка Бейкера, но этого по-прежнему недостаточно ...

"Excel хранит даты как значение с плавающей запятой ..целая часть - это количество дней с 01.01.1900 (или 01.01.1904 в зависимости от того, какой календарь используется), дробная часть - это доля дня (т. е. временная часть) ...немного более неловко из-за того, что 1900 год считается високосным годом.

Единственное, что отличает данные от числа, - это маска формата числа. Если вы можете прочитать маску формата, вы можете использовать ее для идентификациизначение в виде даты, а не числа ... затем вычислите значение / форматирование даты из базовой даты. "

" Но разве атрибут "s" для дат не имеетвсегда значение "1"? Я знаю, что это определяет стиль, но, может быть,?;) "

Атрибут s ссылается на запись стиля xf в styles.xml, и не будетвсегда будет запись 1 для дат ... все зависит от тогоw в книге используется много разных стилей.Стиль xf, в свою очередь, ссылается на маску числового формата.Чтобы идентифицировать ячейку, содержащую дату, вам нужно выполнить поиск в формате xf -> numberformat, а затем определить, является ли эта маска числового формата маской числового формата даты / времени (а не, например, в процентах или маске форматов учетных чисел)

"Еще один вопрос - я сейчас смотрю на содержимое style.xml и в разделе вижу такие элементы, как:"",""и т. д., но нет раздела ... Существуют ли какие-либо" стандартные "форматы? Или я что-то просто пропускаю?"

Может кто-нибудь помочь, пожалуйстаменя нет?Заранее спасибо.

Ответы [ 4 ]

11 голосов
/ 11 января 2011

Вы должны найти раздел numFmts где-то в верхней части style.xml как часть элемента 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>

РЕДАКТИРОВАТЬ

Я былперепроверить мой читательский код xlsx (прошло много времени с тех пор, как я углубился в эту часть библиотеки);и есть встроенные форматы.Коды числового формата (numFmtId) меньше 164 являются «встроенными».

Список, который у меня есть, неполон:

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# ??/??';
8 голосов
/ 09 марта 2011

Клетки могут иметь стили.Это uint, которые индексируют 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: 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; @" /]

Этот код извлекает список стилейИдентификаторы, соответствующие этим форматам даты.

  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 голосов
/ 24 октября 2011

Я хотел бы предложить, чтобы numFmtId = "14" считался "форматом краткой даты Windows", поскольку в Австралии этот формат будет отображать дату как "дд / мм / гг", а не "мм / дд / гг" ».

1 голос
/ 07 сентября 2017

Существует два способа получить формат даты для ячейки.

Вы начинаете с захвата "s" или StyleIndex.Обратите внимание на дату в числовом необработанном формате ниже (40667):

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

Атрибут "s" в узлах ячеек указывает на начинающийся с нуля массив узлов styles.xml, начинающийся с 0. Это ключчтобы найти формат даты, если таковой имеется, который сопоставляется с необработанными числовыми данными даты.Вы видите s = 1, который указывает на второй узел xf в следующем разделе style.xml форматирования ячейки вашей книги Excel:

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

Во втором узле вы видите значение numFmtId = "14".Это число FormatID.Он говорит вам, что это идентификатор, необходимый для определения того, в каком номере должна быть представлена ​​ваша дата. Но это число указывает на два возможных места для формата даты.Если его число находится в диапазоне 14-22, это встроенный стиль для даты.Если он выходит за пределы этого диапазона, его (возможно) пользовательский формат даты добавляется владельцем файла Excel.Вы не будете знать, пока не проверите оба места.

В первом случае, если значение равно 14-22, вам нужно будет сопоставить его с одним из предварительно созданных форматов даты, которые есть в каждом файле excel (mm-дд-гг и т. д.).Вы можете найти эту таблицу в 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 и посмотреть, соответствует ли он одному из приемлемых в вашем коде.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...