Windows起動後の経過時間の取得方法
VBAには経過時間をミリ秒で取得できるTimer関数がありますが、0時になると0ミリ秒にリセットされるため、日付を超える場合は利用できません。
Windowsを起動してからどれぐらいの時間が経っているかを調べるには、Win32API(Windows API)のGetTickCount関数やGetTickCount64関数を利用します。
GetTickCount64関数を使えるのであればそちらをお勧めします。
構文
64bit版です。
Declare PtrSafe Function GetTickCount Lib “kernel32” () As Long
Declare PtrSafe Function GetTickCount64 Lib “kernel32” () As LongLong
GetTickCount戻り値 | Windowsが起動してからどれだけ経過したかをミリ秒で返します。約49.7日まで扱えます。 |
GetTickCount64戻り値 | Windowsが起動してからどれだけ経過したかをミリ秒で返します。通常は約2.9億年まで扱えます。 |
使う方だけを標準モジュールなどの先頭あたりに記述します。
戻り値の範囲
GetTickCount関数は宣言では戻り値がLong型になっていますが、実際の定義では符号なしの32ビットの整数値になります。同様に、GetTickCount64関数の戻り値はLongLong型ですが実際の戻り値は符号なしの64ビットの整数値です。
そのため、扱える値の範囲は以下のようになります。
関数 | 最小値 | 最大値 | 日数・年数換算 |
---|---|---|---|
GetTickCount | 0 | 4,294,967,296 | 約49.7日(4,294,967,296÷(1000ms×60s×60m×24h)=49.7102696296日) |
GetTickCount64 | 0 | 18,446,744,073,709,551,616 | 約5.8億年(18,446,744,073,709,551,616÷(1000ms×60s×60m×24h×365.2425)=584,554,049.254) |
表のとおり、GetTickCount関数とGetTickCount64関数の戻り値は符号なし(マイナス値なし)ですが、VBAのLong型が扱える値の範囲は符号つきの −2,147,483,648 から 2,147,483,647 で、LongLong型は -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807 のため、GetTickCount関数またはGetTickCount64関数の戻り値のほぼ半分の値までしか扱えません。
では、GetTickCount関数で半分(約24.8日)を超えた値が帰ってきた場合どうなるのか、という話になりますが、戻り値をLong型の変数で受け取った場合は2,147,483,647を超えてしまうためオーバーフローとなり異常が発生します。
そこで対応方法としては、戻り値はLong型ではなく64ビットのLongLong型で受け取ればオーバーフローにならずに済みます。LongLong型がないバージョンのExcelであればDouble型でも代用できます。ただ、そういうことを考えるのが面倒であればGetTickCount64関数を使うことをお勧めします。
なお、GetTickCount64関数では最大値が約5.8億年で、「PC起動して5.8億年つけっぱなしにしたらオーバーフローで落っこちました」なんてことはありえないため、考慮不要でLongLong型で受け取ってよいと思います。ただし、約5.8億年は符号なしの場合のため、符号ありのLongLong型では半分の約2.9億年が限度になります。
サンプルコード
GetTickCount関数とGetTickCount64関数のサンプルです。比較としてTimer関数も出力しています。
モジュールの先頭あたりにDeclare~の構文を記述します。
先に書いた説明の通り、GetTickCount関数の戻り値を受け取る変数はLong型ではなくLongLong型で設定しています。LongLong型がない場合はDouble型でも構いません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long Declare PtrSafe Function GetTickCount64 Lib "kernel32" () As LongLong Sub GetTickCountTest() Dim t As LongLong '// DoubleでもOK Dim t64 As LongLong Dim tm As LongLong t = GetTickCount t64 = GetTickCount64 tm = Timer '// ミリ秒 Debug.Print "GetTickCount ミリ秒:" & t Debug.Print "GetTickCount64 ミリ秒:" & t64 Debug.Print "Timer ミリ秒:" & tm '// 秒 Debug.Print "GetTickCount 秒:" & t / 1000 Debug.Print "GetTickCount64 秒:" & t64 / 1000 Debug.Print "Timer 秒:" & tm / 1000 '// 分 Debug.Print "GetTickCount 分:" & t / 1000 / 60 Debug.Print "GetTickCount64 分:" & t64 / 1000 / 60 Debug.Print "Timer 分:" & tm / 1000 / 60 '// 時 Debug.Print "GetTickCount 時:" & t / 1000 / 60 / 60 Debug.Print "GetTickCount64 時:" & t64 / 1000 / 60 / 60 Debug.Print "Timer 時:" & tm / 1000 / 60 / 60 '// 日 Debug.Print "GetTickCount 日:" & t / 1000 / 60 / 60 / 24 Debug.Print "GetTickCount64 日:" & t64 / 1000 / 60 / 60 / 24 Debug.Print "Timer 日:" & tm / 1000 / 60 / 60 / 24 '// 年 Debug.Print "GetTickCount 年:" & t / 1000 / 60 / 60 / 24 / 365.2425 Debug.Print "GetTickCount64 年:" & t64 / 1000 / 60 / 60 / 24 / 365.2425 Debug.Print "Timer 年:" & tm / 1000 / 60 / 60 / 24 / 365.2425 End Sub |
実行結果
GetTickCount ミリ秒:434636359
GetTickCount64 ミリ秒:434636359
Timer ミリ秒:81633
GetTickCount 秒:434636.359
GetTickCount64 秒:434636.359
Timer 秒:81.633
GetTickCount 分:7243.93931666667
GetTickCount64 分:7243.93931666667
Timer 分:1.36055
GetTickCount 時:120.732321944444
GetTickCount64 時:120.732321944444
Timer 時:2.26758333333333E-02
GetTickCount 日:5.03051341435185
GetTickCount64 日:5.03051341435185
Timer 日:9.44826388888889E-04
GetTickCount 年:1.37730779259036E-02
GetTickCount64 年:1.37730779259036E-02
Timer 年:2.58684679052654E-06