TDateTime のナゾ

ほとんどの VCL オブジェクト は TDateTime 型を使って日付値と時刻値を示します。TDateTime 値の整数部は西暦 1899 年 12 月 30 日からの経過日数を示します。小数部はその日の経過時間(24 時間制)です。

んーなぜ 1899/12/30 からなんでしょうね。でもそういえば Visual Basic も日付時刻型って実質浮動小数点値だった気がする。

Date の場合、時刻は 00:00:00 であり、その日の午前0時である。Time の場合日付は1899年12月30日となっているが、これは VB 6 の日付を扱う起点となる日付である。具体的な起点はというと、値がゼロになる位置を表示させれば分かる。VB 6 の日付時刻は倍精度浮動小数点数値で扱われるので、0# の値を渡せば良い。具体的には、プログラムの10行目に書いたとおりである。実行結果を見て分かるとおり、1899/12/30 00:00:00 が起点となる。

連載:プロフェッショナルVB.NETプログラミング 第5回 日付時刻の取得とフォーマット(1/3) - @IT

んあーこっちが先なのか。たぶん*1

まだしも 1899/12/31 00:00:00 を起点とすれば 1900/1/1 が 1 になって心情的に理解できなくもないですが*2,実際には 2 ですよね。謎。

ちなみに(少なくとも Delphi の場合)

TDateTime 値が負の値である場合は,時刻部分を別個に扱わなければなりません。小数部は TDateTime 値の符号とは無関係に 1 日 24 時間の端数を表します。たとえば,1899 年 12 月 29 日の午前 6:00 は -1 + 0.25(-0.75)ではなく -1.25 です。-1 と 0 の間の TDateTime 値は存在しません。

日付・時間の差分の計算が楽になるから浮動小数点値にしてると思ったんですが 1989/12/30 をまたぐと計算がおかしくなりますね。自力で計算するんじゃなくて SecondSpan 等使うほうが吉,と。

追記

なんとなく理由の予想はついたような。TDateTime も TDate も TTime も実質同じ浮動小数点型なわけですが,「時間」だけ(つまり TTime)を扱うなら,日付部分(つまり整数部分)は 0 として利用する局面が多いかと思います。

でもやっぱり 12/30 じゃなくて 12/31 でいいじゃん,と思いますが,おそらく,24:00 (= 1.0)が欲しかったんではないか,と。もちろん時刻としてはありえない値ですが,span として考えたときに 24:00 がやっぱりいるなぁ,じゃあバッファとして2日分にしておくか,と。

憶測にすぎませんが一応。

*1:VB.NET だと基数は 0001/01/01 です。ちなみに Delphi 1.0 もそう。なぜか扱いが逆転してます。

*2:でも 0 のほうが好み