お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

Excelのカラムの時間を取得したい

Yamanaka Yamanaka 3 years
Excelのカラムの時間を取得したい

クライアントエンジニアもサーバ側のCMSの開発も行っている山中です。

「Xlsmファイルの特定シートの値を取得したい」 でExcelファイルをインポートについて話しましたが、 自作のxlsx形式のインポート処理にて 2021-11-24 10:00:00 のデータを入れようとしましたら、 44524.416666666664 と予想外の値がインポートされました。

zipファイルとして展開してsheet1.xmlを開くと

 <c r="E7" s="11">
<v>44524.416666666664</v>
</c>

下記の参考URLによるとこの数値のことを「日付シリアル値」と呼びます。 西暦1900年1月1日午前0時ちょうどを1として、24時間を1として表します。

参考URL:https://www.forguncy.com/blog/20170622_datetime

このs="11"というのがおそらく日時を表しているのかと思いましたがそう単純では無さそうです。

2021-11-24 10:00:00の表示形式を新規Excelで

カラム:A1 分類:日時 種類:2001/3/14 1:30 PM
カラム:A2 分類:日時 種類:2001/3/14 13:30
カラム:A3 分類:時刻 種類:2001/3/14 1:30 PM
カラム:A4 分類:時刻 種類:2001/3/14 13:30
カラム:A5 分類:ユーザー定期 種類:G/標準
カラム:A6 分類:ユーザー定期 種類:yyyy/m/d h:mm
カラム:A7 分類:ユーザー定期 種類:[$-409]yyyy/m/d h:mm AM/PM;@
カラム:A8 分類:ユーザー定期 種類:yyyy/m/d h:mm;@

を作成してsheet1.xmlを確認したら

<row r="1" spans="1:1"><c r="A1" s="2"><v>44524.416666666664</v></c></row>
<row r="2" spans="1:1"><c r="A2" s="3"><v>44524.416666666664</v></c></row>
<row r="3" spans="1:1"><c r="A3" s="2"><v>44524.416666608799</v></c></row>
<row r="4" spans="1:1"><c r="A4" s="3"><v>44524.416666608799</v></c></row>
<row r="5" spans="1:1"><c r="A5" s="4"><v>44524.416666608799</v></c></row>
<row r="6" spans="1:1"><c r="A6" s="1"><v>44524.416666608799</v></c></row>
<row r="7" spans="1:1"><c r="A7" s="2"><v>44524.416666608799</v></c></row>
<row r="8" spans="1:1"><c r="A8" s="3"><v>44524.416666608799</v></c></row>

となるのでs="11"ならば日時というわけでは無さそうです。

s=の番号はstyles.xmlのcellXfs配下のxfの番号を表していました。(0始まり) xfの中でnumFmtIdが表示形式を表しています。

元のエクセルに戻りまして、 2021-11-24 10:00:00は定義された表示形式ではないので、同じstyles.xmlにnumFmtsで定義されています。

<numFmts count="1">
<numFmt numFmtId="176" formatCode="yyyy\-mm\-dd\ hh:mm:ss"/>
</numFmts>

今回の表示形式のみ取得する場合は以下の処理で取得できました。

        // 型が保存されたファイル
        $stylePath = 'xl/styles.xml';
        // ファイルを取りだす
        exec("unzip -p ".$excelPath ." ". $stylePath , $res);
        $data = simplexml_load_string($res[1]);
        $numFmt = $data->numFmts;
        $styleIsTime = [];
        $index = 0;
        foreach ($data->cellXfs->xf as $value) {
            $styleIsTime[$index] = false;
            if(intval($value["numFmtId"]) >= 176){
                foreach ($numFmt->numFmt as $fmt){
                    if(intval($fmt["numFmtId"]) == intval($value["numFmtId"]) && strval($fmt["formatCode"]) == 'yyyy\-mm\-dd\ hh:mm:ss'){
                        $styleIsTime[$index] = true;
                        continue;
                    }
                }
            }
            $index++;
        }

定義された表示形式ならnumFmtIdの数値で判断を行えば問題ないでしょう。 コレで時間だと判断したら、日付シリアル値をタイムスタンプに変換します。 参考URL:https://blog.taka.at/archives/53196027.html

        $get_time = date('Y-m-d H:i:s', ($data-25569.375)*86400);

しかし、2021-11-24 09:59:59と時間が1秒ほどのズレが...

2021-11-24 10:00:00 をExcel上で標準に変えれば44524.4166666667 sheet1.xmlでは 44524.416666666664 後ろの数値が異なります。

取り敢えず少し数値を足して切り上げて対応しました。

        $ceil_round_up = 0.5 * pow(0.1, 11);
        $get_time = date('Y-m-d H:i:s', (round($data+$ceil_round_up,12)-25569.375)*86400);

以上 山中がお伝えしました。またお会いしましょう!

Excelのカラムの時間を取得したい 2021-09-24 09:02:50

コメントはありません。

4209

お気軽に
お問い合わせください。

お問い合わせ
gomibako@aska-ltd.jp