Существующий API для чтения дат из файлов SpreadsheetML?

Существует ли существующий API в Office Open XML SDK или сторонний API для правильного чтения дат из файла SpreadsheetML/.xlsx?

Поскольку существует так много переменных, которые влияют на определение того, когда значение является датой (numFmtId + настраиваемые числовые форматы), а затем преобразование серийного номера даты в значение DateTime (стандартные, обратно совместимые и 1904-супер-обратно-совместимые книги), это кажется логичным, что это то, что предоставит SDK или, по крайней мере, у кого-то будет существующий фрагмент кода для обработки.

Я использую С#, но решение для любого языка будет в порядке.


person Samuel Neff    schedule 20.01.2011    source источник


Ответы (2)


Похоже, что для этой цели уже нет ничего конкретного. Вот рутина, которую я придумал.

/// <summary>
/// Represents the formula used for converting date serial values stored within the workbook into DateTime instances.
/// </summary>
/// <remarks>
/// Information on date serial conversion is available here: http://www.documentinteropinitiative.com/implnotes/ISO-IEC29500-2008/001.018.017.004.001.000.000.aspx
/// </remarks>
public enum XlsxDateCompatibility
{
    /// <summary>
    /// Standard dates are based on December 30, 1899 and are considered "Standard 1900" dates.
    /// </summary>
    StandardBase1900,

    /// <summary>
    /// Excel for Windows backwards compatible dates are based on December 31, 1899 are are considered "Backwards compatible 1900" dates.
    /// </summary>
    BackwardsCompatibleBase1900,

    /// <summary>
    /// Excel for Macintos backwards compatible dates are based on January 1, 1904 and are considered "1904" dates.
    /// </summary>
    BackwardsCompatibleBase1904
}

    private static readonly IDictionary<XlsxDateCompatibility, DateTime> _dateSerialBaseDates
        = new Dictionary<XlsxDateCompatibility, DateTime>
            {
                {XlsxDateCompatibility.StandardBase1900, new DateTime(1899, 12, 30)},
                {XlsxDateCompatibility.BackwardsCompatibleBase1900, new DateTime(1899, 12, 31)},
                {XlsxDateCompatibility.BackwardsCompatibleBase1904, new DateTime(1904, 1, 1)}
            };

    public static DateTime DateSerialToDateTime(double dateSerial, XlsxDateCompatibility dateCompatibility)
    {

        // special case for dateCompaitility 1900, Excel thinks 1900 is a leap year
        // http://support.microsoft.com/kb/214019
        if (dateCompatibility == XlsxDateCompatibility.BackwardsCompatibleBase1900 && dateSerial >= 61.0)
        {
            dateSerial -= 1;
        }

        DateTime baseDate;          
        if (!_dateSerialBaseDates.TryGetValue(dateCompatibility, out baseDate))
        {
            baseDate = _dateSerialBaseDates[XlsxDateCompatibility.StandardBase1900];
        }
        return baseDate.AddDays(dateSerial);
    }
person Samuel Neff    schedule 18.02.2011

Я никогда раньше не читал дату, но я думаю, вам придется сравнить индекс стиля в ячейке, которую вы читаете, с индексом стиля даты в элементе x:numFmts, который вы найдете в элементе x:cellStyle. Я знаю, что в Office 2010 есть индикатор типа данных даты в ячейке, где <x:c t='d'>, поэтому, если вы используете эту версию, было бы намного проще найти, являются ли данные датой или нет. Вот как это будет выглядеть в Office 2010:

<x:c r="C4" t="d"> 
   <x:v>1976-11-22T08:30Z</x:v>
</x:c> 

Чтобы преобразовать данные в DateTime, я считаю, что все, что вам нужно сделать, это DateTime.FromOADate(cellvalue), где cellValue - это двойное значение. Я знаю, что мы конвертируем DateTime в OADate перед вставкой дат в наши документы Excel, поэтому я полагаю, что использование метода FromOADate будет работать нормально.

Что касается каких-либо API для выполнения этих функций, я не знаю ни одного, который будет выполнять то, что вы хотите, но я бы хотел, чтобы он был включен в будущие версии SDK.

person amurra    schedule 20.01.2011
comment
Спасибо за ваши комментарии. Я уже задавал и получил хорошие ответы на вопросы об определении дат и технических деталях их чтения. На самом деле это намного сложнее, чем показывает ваш ответ. У меня достаточно информации, чтобы написать собственный код для чтения дат сейчас, но меня внезапно осенила мысль, что это должно быть распространенной проблемой, и я был удивлен, что не смог найти никакого существующего кода для ее обработки. - person Samuel Neff; 20.01.2011
comment
@Samuel - Да, мой ответ - это взгляд с высоты 50 000 футов на то, как я мог бы начать решать, как идентифицировать даты в Excel, но вы определенно правы, говоря, что это сложнее, чем то, что я написал. Если вам случится это выяснить, я хотел бы увидеть код, так как трудно найти ответы на основные вопросы Open XML SDK. - person amurra; 20.01.2011
comment
когда закончу, выложу проект. Я почти закончил работу с конвертером xlsx в DataSet с использованием обработки в стиле SAX из Open XML SDK. - person Samuel Neff; 20.01.2011
comment
@ Самуэль - Круто. С нетерпением жду этого. - person amurra; 20.01.2011