さよなら備忘録

「なにをいまさら」と言われそうな些細なことのメモがわり

Windowsで時刻を手動変更したときのC++への影響

結論から書くとどうしてこうなるのか全くわかってません。
各仕様や実装の誤解が多分にあると思われるのでご注意下さい。


Windows環境で時刻を手動で変更したときにC++の時間関連のプログラムにどう影響があるかコードを動かしてみました。
検証方法は単純にデバッグでステップ実行しつつ、時刻を変更してどうなるか見てみるだけです。

動作環境はWindows7コンパイラはVisualStudio2013。

clock()

プログラム起動からの経過時刻を取得するC言語の関数。
以下のコードで(1)実行後に時刻を巻き戻すると、(2)で負数が返された。
時刻の変更の影響を受けているようです。

#include <ctime>
#include <iostream>
using namespace std;
int main() {
  cout << clock() / CLOCKS_PER_SEC << endl; // (1)
  cout << clock() / CLOCKS_PER_SEC << endl; // (2)
}
GetTickCount()

システム起動からの経過時刻を取得するWindowsAPI。
(1)実行後に時刻を巻き戻しても(2)は正常に経過した値が返されました。
時刻の変更の影響を受けていないようです。

#include <iostream>
#include <windows.h>
using namespace std;
int main() {
  cout << GetTickCount() << endl; // (1)
  cout << GetTickCount() << endl; // (2)
}
steady_clock

C++11で追加された時刻が逆行しないことが保証されるクロック。
(1)実行後に時刻を巻き戻したら、(2)で負数が返された。
逆行しないことが保証されているので影響しないと予想していましたが、こちらも影響を受けるようです。
steady_clockに対する自分の認識が間違っている可能性が大ですが…

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
  auto begin = steady_clock::now(); // (1)
  cout << duration_cast<seconds>(steady_clock::now() - begin).count() << endl; // (2)
}


thread::sleep_until() へパラメータとなる場合も検証してみました。
(1)で再開時刻を取得したあとに時刻を巻き戻すと、5秒経ってもsleepから戻ってきませんでした。

#include <chrono>
#include <thread>
using namespace std;
using namespace std::chrono;
int main() {
  auto t = steady_clock::now() + seconds(5); // (1)
  this_thread::sleep_until(t);
}

steady_clock の実装は system_clock を public 継承しているだけだったので、
VisualStudioでは steady_clock と system_clock に差はないのかもしれませんね…



とりあえずWindowsAPI以外は全て影響を受けるようです。
マルチプラットフォームで時刻の手動変更の影響を受けないような関数は標準にないのかな…?
Boostライブラリのchronoがどうなっているかも調べたほうがよいのかもしれません。