OSが起動したときの時刻をTDateTime型で取得したいのですが
やりかたが分かりません。
どなたか分かる方おしえてください。お願いします。
OSが起動した時刻を直接求める方法は分かりませんが、
おおよその時刻であれば、GetTickCount API で起動してからの経過時間が得られますので、現在の時刻より逆算すれば得られます。
GetTickCountが返す型はIntegerで、単位はミリ秒です。
秒単位で欲しければ1000で割ることになります。
失礼しました。
その値をTDateTime型で得たいのでしたね。
起動時刻ではありませんが、起動後の経過時間をTDateTime型に変換する例です。
procedure TForm1.Button1Click(Sender: TObject);
var
TimeStamp: TTimeStamp;
DateTime: TDateTime;
begin
TimeStamp := MSecsToTimeStamp(GetTickCount);
DateTime := TimeStampToDateTime(TimeStamp);
Showmessage(TimeToStr(DateTime));
end;
GetTickCount の戻り値は DWORD なので、およそ 49.7 日でカウントアップ
するのが問題なんですよね。そこをクリアできればいいんですけど。
つまり起動時刻が知りたければ
現在の時刻から経過時間をひけばいいのですね?
しかし、
procedure TForm1.Button1Click(Sender: TObject);
var
TimeStamp: TTimeStamp;
DateTime: TDateTime;
begin
TimeStamp := MSecsToTimeStamp(GetTickCount);
DateTime := TimeStampToDateTime(TimeStamp);
Showmessage(DateTimeToStr(Now - DateTime));
end;
と書いたらおかしな値がでました
どこかおかしいですか?
>と書いたらおかしな値がでました。どこかおかしいですか?
ということは、私のコードでエラーにならなかったのですね。
TimeStampは時間だけを得る関数で、DateTimeは日付と時刻。
Now - DateTimeとやってしまうと、年月の引き算も入ってしまっておかしな値が生まれますが、333さんが書いているように、GetTickCount の戻り値は DWORD。
TTimeStamp型に代入できて処理できてしまうのは変だと引っかかっていたのですが、Delphi3だと通ってしまうようです。
Delphi6で試したらエラーになりました。というわけで、私のコードは誤りです。
また、「逆算すれば得られます」と簡単に書いてしまいましたが、結構面倒ですね。
Delphi6でテストしたコードを載せます。
ただし、午前0時をまたぐ場合については、更に条件分岐が必要となります。
また、333さんの言う49時間も、その場合にはお手上げでしょう。
Windowsが起動したときに、出勤時刻をどこかに記録していてくれない限り。
procedure TForm1.Button1Click(Sender: TObject);
var
StartTime: TDateTime;
NowMse, PastMse, StartMse: LongInt;
StartH, StartM, StartS, StartMs, TempS: Word;
begin
// 現在時刻を本日の0時から経過したミリ秒で得る
NowMse := MilliSecondOfTheDay(Now);
// 起動時からの経過時間をミリ秒で得る
PastMse := GettickCount;
// 起動時刻を本日の0時から経過したミリ秒数で得る
StartMse := NowMse - PastMse;
// 起動時刻を時分秒ミリ秒に分ける
TempS := StartMse div 1000;
StartH := TempS div 3600;
StartM := TempS div 60 mod 60;
StartS := TempS mod 60;
StartMs := StartMse mod 1000;
// TdateTime型を生成する
StartTime := EnCodeTime(StartH, StartM, StartS, StartMs);
Showmessage(TimeToStr(StartTime));
end;
日付はdouble型ですから、そんなに難しく考えることはないと思いますよ。
procedure TForm1.Button2Click(Sender: TObject);
var
d: double;
n: TDateTime;
begin
d := GetTickCount;
n := Now;
d := ((((d / 1000) / 60) / 60) / 24); // 変換(ミリ秒->秒->分->時間->日)
n := n - d; // 現在時刻から起動後の時間を引く
ShowMessage(DateTimeToStr(n));
end;
にしのさんwrote
>d := ((((d / 1000) / 60) / 60) / 24);
そうだ。日にちに合わせればTDateTime型の値になったのだ。
思いつきませんでした。
習わないと分らないことでした。感謝。
にしのさんのレス内容は、真っ先に浮かびましたが、
49.7 日でカウントアップ
この問題が解決出来ないので書きませんでした。
GetTickCount だけでは、正確な起動時刻は分からないのでは?
検索していくつか答えらしきものを見つけましたけど、どうも
自分のところではうまくいっていません。
にしのさんの方法でうまくいくことができました。
49.7日でカウントアップということですが、
解決方法などが見つかりましたらまた御教授ください。
ソース付きで詳しく解説してくださってありがとうございました。
レジストリに起動日時が書いてありそうですが、見つかりませんでした。
# ShutdownTimeというのはあったのですが、バイナリでSYSTEMTIMEなのかFILETIMEなのかも未確認
月に1度GetTimeCountをチェックして、カウントアップのチェックを行えば誤魔化せます。
常駐でなくても、タスクに登録しておけばよろしいかと。
うーむ、それならスタートアップに登録して、起動時刻をファイルかレジストリに
記録するだけのアプリのほうがよいのではないでしょうか。
GetTickCountがいつから開始するか正確なことはわかりませんが、スタートアップだとかなりずれますよ。
> スタートアップだとかなりずれますよ。
えーと、どのくらい正確なのが必要かんもよりますが、20秒くらいならいいんでは。
> 月に1度GetTimeCountをチェックして、カウントアップのチェックを行えば誤魔化せます。
これよりかなりましだと思いますけど。月に1度、忘れないで実行するのは難しい
と思います。
> これよりかなりましだと思いますけど。月に1度、忘れないで実行するのは難しい
> と思います。
これは、
> 常駐でなくても、タスクに登録しておけばよろしいかと。
と書いたように、タスクで月に一度実行させればよいかと思います。ウィルスチェックを週一度するのと同じような物です。
同じ間隔で、カウントアップの時間(47.9日)以内であれば、カウントアップしたかどうかの判別は大小の比較だけでできますから。
タスクが消されるかもしれないという問題は、スタートアップも同程度ですし。
> カウントアップしたかどうかの判別は大小の比較だけでできますから。
そうですね。GetTickCount で現在の数値が前回記録されたのより小さければ
カウントアップしたということで、レジストリかファイルかにあるカウントアップ
した回数を記録する数値をインクリメントするのでしょう。しかし、その場合、
新規に起動されて数値が小さくなった場合とどうやって区別しますか?
起動時刻を記録したほうが簡単だと思います。
> 新規に起動されて数値が小さくなった場合とどうやって区別しますか?
普通に考えれば、コマンドオプションをつけてタスクに登録でしょう。
スタートアップに登録されたショートカットを実行された場合も、同様の考慮が必要だと思いますが。
> 起動時刻を記録したほうが簡単だと思います。
考えてみたら、スタートアップでGetTickCountから逆算した起動時刻を記録であれば、こっちのほうが簡単ですね。
# 投稿者がどの程度の精度を必要としているかにもよります
ショートカットだと上に書いたような問題が残ってしまうので、やはりレジストリのrunでしょうか。
面倒ですが、サービスに登録してしまう(常駐させてしまう)という手もあります。
ツイート | ![]() |