[不具合あり] C++ Builder XE4 > TTimer > 指定時刻(hh, mm)に処理をする > TTimer->Intervalの設定 > テストしにくい

**注意: 2018/01/05 下記のコードには不具合があります。ミリ秒の差が検討されていないため、タイマー処理が失敗します。修正版(v0.2)は下記に記載しました。**

[C++ Builder 10.2 Tokyo > 実装ミス > タイマー処理関連 > 指定時刻(hh, mm)に処理をする > 処理時刻のずれがある > 修正版v0.2](https://qiita.com/7of9/items/668d63cc52456a134959)

```txt:動作環境
C++ Builder XE4
```

---

### 処理概要

- Timeのhhとmmを指定する
- (時==hh)と(分==mm)となる日時に処理をする
- 現在時刻と指定時刻が一致する場合は、次の日とする

TTimer->Intervalを使った実装とした。
    
### code v0.1

```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 で管理されるコンポーネント
	TEdit *E_hh;
	TEdit *E_mm;
	TButton *B_start;
	TMemo *Memo1;
	TLabel *Label1;
	TTimer *TimerAlarm;
	void __fastcall B_startClick(TObject *Sender);
	void __fastcall TimerAlarmTimer(TObject *Sender);
private:	// ユーザー宣言
	TDateTime __fastcall getNextAlarmDateTime(TDateTime now, int hh, int mm);
	void __fastcall startAlarmTimer(void);
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;
//---------------------------------------------------------------------------

/*
v0.1 Oct. 18, 2017
	- add startAlarmTimer()
	- add [TimerAlarm]
	- add getNextAlarmDateTime()
*/

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	TimerAlarm->Enabled = false;
}
//---------------------------------------------------------------------------

TDateTime __fastcall TForm1::getNextAlarmDateTime(TDateTime now, int hh, int mm)
{
	TDateTime res = RecodeHour(Now(), hh);
	res = RecodeMinute(res, mm);
	res = RecodeSecond(res, 0);
	if (res <= Now()) {
		res = IncDay(res, 1);
	}
	return res;
}

void __fastcall TForm1::B_startClick(TObject *Sender)
{
	startAlarmTimer();
}

void __fastcall TForm1::startAlarmTimer(void)
{
	// 1. フォームからの読取り
	int next_hh, next_mm;
	try {
		next_hh = StrToIntDef(E_hh->Text, -1);
		next_mm = StrToIntDef(E_mm->Text, -1);
	} catch (Exception &exc) {
		ShowMessage(exc.Message);
		return;
	}
	if (next_hh < 0 || next_mm < 0) {
		Memo1->Lines->Add(L"Error: set numerical values for [hh] and [mm]");
		return; // error
	}

	// 2. 次の日時取得
	TDateTime nextdt = getNextAlarmDateTime(Now(), next_hh, next_mm);

	String msg = "now: " + Now().DateTimeString() + L" next: " + nextdt.DateTimeString();
	Memo1->Lines->Add(msg);

	// 3. タイマーセット
	__int64 intvl = SecondsBetween(Now(), nextdt);
	TimerAlarm->Enabled = false;
	TimerAlarm->Interval = intvl * 1000; // msec
	TimerAlarm->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerAlarmTimer(TObject *Sender)
{
	TimerAlarm->Enabled = false;

	String msg = L"Expired @ " + Now().DateTimeString();
	Memo1->Lines->Add(msg);

	startAlarmTimer();
}
//---------------------------------------------------------------------------

```

### 結果

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/7c29b8bc-f0c6-25ef-e250-8066e129d246.png)

OnTimerにてstartAlarmTimer()をコールすることで繰返し処理をすることはできる。

現状の問題はテストをしにくい点。1日1回のイベントを数日かけてテストするのは効率が悪い。