W.I.S. Laboratory
menu-bar

Excel


ExcelのDATE形式とVBAのDATE形式で、同じ値なのに日付が1日ズレる

例えばエクセルのセルに「1900/1/20」と入力し、これをVBAからDate形式で取得してMsgbox命令で表示すると「1900/1/19」と出てくるという厄介な現象がある。
同じシリアル値なのに、VBAだとセル内容に比べて1日前の日付になってしまうのだ。

Sub sample()
 Dim D As Date
 D = Cells(1, 1) ' セルA1には「1900/1/20」と入っている
 Cells(2, 1) = D ' こうすると「1900/1/20」と入る
 MsgBox (D) ' 何故か「1900/1/19」と出る
End Sub

なんでこんなことになるかというと、エクセルのDATE形式は「1900/1/1」をシリアル値1とする連番として扱うのに、VBAのDATE形式は「1899/12/31」をシリアル値1とする連番として扱うからだ。
エクセル側のみ、グレゴリオ暦では存在しないはずの「1900/2/29」が存在し、VBA側で辻褄を合わせるために「1900/2/28」以前の連番が1つずつズレている。
そのため、VBAでは「1900/1/1」がシリアル値2になり、シリアル値1を存在させるために「1899/12/31」がやむを得ず必要となった。

このようになった経緯はLotus1-2-3まで遡るようだ。
グレゴリオ暦の閏年は4年に1回あるのだが、例外として100年に1回無く、400年に1回ある。
1900年がこの「100年に1回無い年」なのだが、Lotus1-2-3のカレンダー処理はこの年を閏年として処理していたらしい。
これがバグか仕様かは分からないが、西暦2000年は「400年に1回ある」という例外の年なので、1900年さえ無視すればLotus1-2-3が作られた年から100年以上問題が発生しないことになる。
閏年の例外を考慮しなければそれだけプログラムがシンプルになり動作も速くなるので、意図的な仕様だったのかもしれない。
そして西暦1900年というような遥か昔の日付を使用することはまず無いので、これが問題になることはほぼなかったようだ。

そしてMicrosoftがExcelを作り始めたとき、すでにLotus1-2-3が世の中に普及していたため、バグも仕様も1-2-3に合わせたらしい。
その後VBAが作られたときに、VBAはExcel側の仕様に合わせることをせず、正確なグレゴリオ暦のカレンダー処理を行うようにした。
これも確かな理由は分からないが、VBAが作られたときにはすでにコンピュータの性能が上がり正確な計算をしても処理がそれほど遅くならない時代になっていたからかもしれない。
ともかくこういった経緯の末、VBA側とExcel側で1日のズレが生じることになり、それ以後互換性のために最新版までずっと引きずられている。


[ 戻る ]
saluteweb