Excelの1900/2/29問題は仕様です!?

f:id:boost-up:20171215204329j:plain

今日は何となく1900/2/29問題のことを思い出しましたので、事象と背景について書いてみたいと思います。

1900/2/29問題ってそもそも何?

おそらく、普段Excelを仕事に活用されている方でも、1900/2/29問題を知っている人の方が少ないと思いますが、この問題は実際には存在しない1900/2/29という日付をExcelが有効な日付と認識している現象です。

言葉で説明するよりも実例を見て頂いた方が分かりやすいと思いますので、下のキャプチャをご覧ください。

f:id:boost-up:20171215194119p:plain

A列とB列には同じ年月日を入力しており、書式設定をA列は「日付」、B列は「標準」にしています。 Excelの日付は1900/1/1を1日目としてカウントしていきますので、3行目の1900/1/1が1となります。

2行目の1899/12/31は有効な日付と認識されず、文字として認識されています(左寄せになっていることがお判りでしょうか?)。 そして、5行目の1900/2/28は1900/1/1から数えて59日目ということになります。

ここまでは普通の話なのですが、問題は6行目にある1900/2/29です。

理屈は一旦横において、実際には1900/2/29という日は存在しません(でした)ので、本来は1900/3/1が60日目にならないと不味いのですが、1900/2/29が60日目となったことにより、1900/3/1以降が1日ずつズレてしまっている事象、これがExcelの1900/2/29問題です。

うるう年の計算方法

うるう年には2/29が存在しますが、多くの方は4年に1回開催される夏季オリンピックの年がうるう年だと記憶していると思います。 実生活において問題ないので私もその一人です。

ただし、実際には上記の理解には2つの例外があります。

1つ目は、西暦を100で割って割り切れる年にはうるう年は存在しないというルールです。 このルールによって、1900年には2/29が存在しないことになるのです。

ちょっと待って、前回の西暦2000年にはうるう年があったよ!?って方、とても鋭いです。

これが2つ目の例外で、西暦を400で割って割り切れる年にはうるう年が存在するという、今この世に生きている我々はこの先誰も経験することのできない超例外ルールが適用されたのが、前回の西暦2000年だったのです。

1900/2/29問題はバグではないのか?

話を元に戻しますが、この問題のことをExcelのバグだと言う方がいるのですが、Microsoftはこれを「仕様」と明言しています。

例えば、Microsoftの公式サポートサイトでは次のような記述を見つけることができます。

Excel では、日付/時刻を内部でシリアル値として処理しています。Excel は他の表計算ソフトで使用される日付システムとの互換性を保つため、1900 年を閏年と解釈し、1900/2/29 が存在するように設計されています。Excel が外部データの取り込みを行う際には、1900/2/29 までのシリアル値が Excel の内部処理により自動的に修正されます。

https://support.microsoft.com/ja-jp/help/967188

ここでいう「他の表計算ソフト」というのは、Microsoft Excel以前に表計算ソフトの分野のデファクトスタンダードの地位にあった「Lotus 1-2-3」のことを指すと言われています。

Lotus 1-2-3のことはもう気にしなくていいんじゃないの?

Windows 95が発売され、一般家庭にパソコンが普及した頃は、Lotus 1-2-3がプリインストールされているパソコンが多かった記憶がありますが、2017年の現在において、少なくとも私の周りにおいてLotus 1-2-3を使っている人は、噂含めて皆無です。 そもそものロータス社自身もIBMに買収されてしまい、ブランドも再編されてしまいました。

Microsoftが未だにLotus 1-2-3自体を意識しているとは考えにくいですが、Lotus 1-2-3と互換性があることを前提に作られた当時のExcel資産は、まだ現役だったりすることもあるのかも知れません。

そういった、これまで生き残ってきたレガシーExcelともなると、もはや中身を理解してお守りをできる人がいないことが多く、解読できないことが更に寿命を延ばす理由になっていたりします。

私見ですが、MicrosoftはLotus 1-2-3との互換性ではなく、旧バージョンのExcelとの互換性を維持することを意識して、この仕様を残しているのだと思います。

結局1900/2/29が存在すると何が困るの?

「仮に1900/2/29が存在したところで、今更困ることはないだろう」 そんな声が聞こえてくるのはごもっともですが、実は私が1900/2/29問題を認知したのは、その「困ったこと」が起きたことがきっかけでした。

そのとき問題が起きていなければ、私も1900/2/29問題なんてものに関心を示すこともなかったと思います。

ExcelとVBA(いわゆるマクロ)で扱いが違う!!

下の画面キャプチャを見てください。先ほどのExcelの日付と同じ日付をメッセージボックスに表示するサンプルです。 (VBAは”#”で囲むと日付形式であることを意味します。)

f:id:boost-up:20171215202739p:plain

赤字になっている箇所がVBAの構文エラーです。 Excelでは有効である1900/2/29がエラーになっているのがお判りでしょうか。 もう一つ、Excelで無効である1899/12/31が有効な日付と解釈されていることもお気付きでしょうか。

この挙動のせいで、VBAで組んだプログラムが予期せぬ動作をしたのです。

Microsoft様、VBAはMicrosoft社謹製のプログラム言語であり、Lotus 1-2-3とは無関係のはずですが、これも「仕様」でしょうか?

おまけ

Excelのオプションを見ると、ブックの計算を「1904年から計算する」というオプションがあります。 f:id:boost-up:20171215203633p:plain

これにチェックを付すと、1900/1/1が1ではなく、1904/1/1が1となるのですが、 不用意にチェックしてしまうと、Excelに入力した日付形式のセルが軒並み4年程ズレるという多大なる影響が生じます。

今のところ、このオプションが必要になるシーンが想像できませんが、 どなたかご存知でしたら教えてくださいませ。