動作環境
C++ Builder XE4
蓄積する誤差
- TTimerを1,000ミリ秒で動かす
- 1,014ミリ秒程度のインターバルになる
- 実測
- 1,014ミリ秒程度のインターバルになる
14ミリ秒の誤差は86400秒/日で1秒/回コールすると
86400 * 14 / 1000 = 1209.6秒のずれになる。
蓄積しないための実装を検討した。
実装案
- 別のタイマー(アラームタイマー)を用意
- TTimerは短いインターバル(例:100ミリ秒)で実施する
- TTimer内でアラームタイマーの時刻と現在時刻を比較する
実装例
Unit1.h
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TTimer *Timer1;
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall FormShow(TObject *Sender);
private: // ユーザー宣言
TDateTime m_nextAlarm; // 次のアラーム時刻
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Timer1->Enabled = false;
Timer1->Interval = 100; // 55ミリ秒以下にはしない (発火しない)
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
if (Now() < m_nextAlarm) {
return;
}
m_nextAlarm = IncSecond(m_nextAlarm, 1);
OutputDebugString(Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz").c_str());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
m_nextAlarm = Now();
}
//---------------------------------------------------------------------------
動作例
デバッグ出力: 2018/12/06 12:05:24.772 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:25.758 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:26.735 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:27.721 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:28.704 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:29.687 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:30.779 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:31.763 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:32.743 プロセス Project1.exe (1348)
(中略)
デバッグ出力: 2018/12/06 12:08:35.728 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:36.709 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:37.689 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:38.785 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:39.768 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:40.749 プロセス Project1.exe (1348)
100ミリ秒程度の誤差であるが、その誤差は蓄積されない。