Strict Open XML Spreadsheet 形式の日付データ

Excel 2013 でサポートされた Strict Open XML Spreadsheet 形式では、日付データの保持の仕方が通常のブックと異なり、プログラム中から直接扱うには個別の処理が必要になります。


通常のブック(Strict でない)では、日付のデータはシリアル値として保持されます。.NET 環境でこのデータを日付として読み込むには、Convert クラスの ToDateTime メソッドを使用します。また、データを設定する場合は、DateTime 構造体の ToOADate メソッドで変換した値を設定します。

通常のブック(Strict でない)の xl/worksheets/sheet1.xml データ部分

<sheetData>
  <row r="1" spans="1:1" x14ac:dyDescent="0.15">
    <c r="A1" s="1">
      <v>41229</v>
    </c>
  </row>
</sheetData>


Strict Open XML Spreadsheet 形式では、v タグに ISO 8601 の形式で保持されます。また、c タグに属性 t=”d” が設定されます。

Strict Open XML Spreadsheet 形式の xl/worksheets/sheet1.xml データ部分

<sheetData>
  <row r="1" spans="1:1" x14ac:dyDescent="0.15">
    <c r="A1" s="1" t="d">
      <v>2012-11-16</v>
    </c>
  </row>
</sheetData>


◆設定する日付データ文字列の作成

プログラム中から Strict Open XML Spreadsheet 形式の日付データを設定するには、DateTime 構造体の ToString メソッドを使用して ISO8601 形式の文字列を作成し、v タグにセルのデータとして設定します。データだけを扱う場合はこれだけでよいのですが、正しく日付のデータとして認識させるには、一つ上の階層の c タグに属性 t=”d” を設定する必要があります。また、日付のデータはセルの書式と組み合わせて使用されるため、書式の番号(xl/styles.xml で定義)も c タグの属性として必要になります。ファイルそのものが Strict Open XML Spreadsheet 形式であるという前提の処理になります。

class Program
{
    static void Main(string[] args)
    {
        string s1 = DateTime.Now.ToString("s");  // 並べ替え可能な日付と時刻のパターン(ISO8601 準拠)
        string s2 = DateTime.Now.ToString("o");  // ラウンド トリップする日付と時刻のパターン(ISO8601 準拠)
        string s3 = DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");
        string s4 = DateTime.Now.ToString("yyyy-MM-dd");
        Console.WriteLine("s1=[{0}]", s1);
        Console.WriteLine("s2=[{0}]", s2);
        Console.WriteLine("s3=[{0}]", s3);
        Console.WriteLine("s4=[{0}]", s4);
    }
}

実行結果


◆取得した日付データの扱い

プログラム中から Strict Open XML Spreadsheet 形式の日付データを取得する場合、XML から取得したテキストを DateTime 構造体の Parse メソッドを使用して DateTime 構造体に格納することができます。この場合、取得の際に設定されているデータがどういったものかを判定する必要がありますが、c タグの t 属性で判定ができます。それだけでなく、ファイルそのものが Strict Open XML Spreadsheet 形式かどうかについても判定が必要です。その場合はいくつか判定方法があると思いますが、xl/workbook.xml の に設定された conformance 属性で判定するのがよいと思います。先ほど設定で使用したデータをそのまま使います。

class Program
{
    static void Main(string[] args)
    {
        DateTime d1 = DateTime.Parse(s1);  // 並べ替え可能な日付と時刻のパターン(ISO 8601 準拠)
        DateTime d2 = DateTime.Parse(s2);  // ラウンド トリップする日付と時刻のパターン(ISO 8601 準拠)
        DateTime d3 = DateTime.ParseExact(s3, "yyyy-MM-dd'T'HH:mm:ss'Z'", null);
        DateTime d4 = DateTime.Parse(s4);
        Console.WriteLine("d1=[{0}]", d1.ToString());
        Console.WriteLine("d2=[{0}]", d2.ToString());
        Console.WriteLine("d3=[{0}]", d3.ToString());
        Console.WriteLine("d4=[{0}]", d4.ToString());
    }
}

実行結果


◆まとめ

Strict Open XML Spreadsheet 形式の日付データそのものは DateTime クラスのメソッドで比較的簡単に扱えますが、そのファイルが Strict Open XML Spreadsheet 形式 かどうかを判定したり、c タグの属性の扱いを考慮すると、少し処理が面倒そうです。
アドバンスソフトウェアで開発しているコンポーネントでも Strict Open XML Spreadsheet 形式への対応を進めており、上記の形式の違いや面倒な処理の部分をあまり意識せず使用できるよう調整中です。

You can leave a response, or trackback from your own site.

Leave a Reply