LoginSignup
7
3

Windows の DATE 型 のとても思いがけない仕様

Last updated at Posted at 2023-09-10

これはなに?

Microsoft の DATE 型のドキュメントの内容が思いがけなさ過ぎて変な声がでるぐらいだったので、この驚きを可視化してシェアしようと思って書いた記事。

その文書

下記リンクがその文書。

びっくりポイントは

日付は、1899 年 12 月 30 日の真夜中を 0 として始まる、整数の増分で表されます。 時間の値は、数値の小数部分の絶対値で表されます。

日付値の整数部分は符号付きとして扱われ、小数部分は符号なしとして扱われる

の部分。(強調引用者)

計算して可視化する

文書だとよくわからないので、実際に計算してみる。

c++_on_Windows
#include <iostream>
#include <ATLComTime.h>
int main()
{
    for (int i = -48; i <= 48; ++i) {
        auto d = COleDateTime(1899, 12, 30, 0, 0, 0) 
               + COleDateTimeSpan(0, i, 0, 0);
        std::cout << i << "," << d << "\n";
    }
    return 0;
}

i は、1899年 12月 30日 午前0時 からの経過時間。単位は時間。つまり i=-12 で 基準時刻の半日前、i=24 で一日後。横軸。
d は、DATE 型 の中に入っている double 型の値。縦軸。

グラフにすると、下図。

image.png

日付が -2日 から -1日に 変わるときに以下のようになる。
下表は 日付が変わる瞬間の プラスマイナス 1万分の1 のふたつの時刻。

整数部 小数部 DATE の値
変わる直前 -2 0.9999 -2.9999
変わった直後 -1 0.0001 -1.0001

のようなことになる。小数部が繰り上がって整数部が増える、というところだけみるとまあそうかなと思うかもしれないけど、 DATE の値 の欄を見ると分かる通り、極めて思いがけない動きとなっている。

困るポイント

DATE 型だから実質 double だよね。と思って double として整列すると順序通りにならない。

時刻の差を見るために double だと思って引き算をするのもだめ。

対策

DATE 型の中身を「どうせ double だよね」と思って操作してはいけない。

感想

Windows アプリケーションを作る仕事もだいぶやったことがあるんだけど、全然気づかなかった。
百年前の時間を扱うことがないので発現しなかったんだと思う。

いにしえのミスによりこうなってしまって、それを前提としたソフトがたくさんあるので直せないまま 30年が過ぎた、とかだと思う。

ミスとしてはわりと酷いものだと思うけど、後方互換性にかける執着心みたいなものの凄みを感じる。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3