LoginSignup
0
0

More than 5 years have passed since last update.

C++ Builder XE4, 10.2 Tokyo > 実装ミス > タイマー処理関連 > 指定時刻(hh, mm)に処理をする > 処理時刻のずれがある > 修正版v0.2

Last updated at Posted at 2018-01-05
動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2

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

上記のXE4の実装を10.2 Tokyoで試した。

code

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 *Button1;
    TMemo *Memo1;
    TLabel *Label1;
    TTimer *TimerAlarm;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall TimerAlarmTimer(TObject *Sender);
private:    // ユーザー宣言
    TDateTime __fastcall TForm1::getNextAlarmDateTime(TDateTime now, int hh, int mm);
    void __fastcall TForm1::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;
//---------------------------------------------------------------------------
__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::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::Button1Click(TObject *Sender)
{
    startAlarmTimer();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerAlarmTimer(TObject *Sender)
{
    TimerAlarm->Enabled = false;

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

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

実行

qiita.png

  • 期待動作
    • 13:19:00にExpiredになる
  • 実動作
    • 13:18:59にExpiredになる
    • 結果、次のタイマーが再度13:19:00になる
    • ミリ秒まで確認したところ、ミリ秒は954あたりになっている

XE4ではきちんと動作していた処理が、10.2 Tokyoでは失敗する。

10.2 Tokyoへ移植時に似たようなタイマー処理をしている部分は全滅しそう。
看過できない不具合だ。

XE4で同じ処理を実行したところ、同じ結果になった。
何かを見落としているのかもしれない。
c++ builder > TDateTime > SecondsBetween() > 秒未満の切捨てに注意をする
c++ builder XE4, 10.2 Tokyo > TDateTime > SecondsBetween() > msecの違い
が関係しているのかもしれない。

code v0.2

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 *Button1;
    TMemo *Memo1;
    TLabel *Label1;
    TTimer *TimerAlarm;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall TimerAlarmTimer(TObject *Sender);
private:    // ユーザー宣言
    TDateTime __fastcall TForm1::getNextAlarmDateTime(TDateTime now, int hh, int mm);
    void __fastcall TForm1::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;
//---------------------------------------------------------------------------
__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::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_sec = SecondsBetween(Now(), nextdt);
    __int64 intvl_msec = MilliSecondsBetween(Now(), nextdt);
    TimerAlarm->Enabled = false;
    TimerAlarm->Interval = intvl_msec; // msec
    TimerAlarm->Enabled = true;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    startAlarmTimer();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerAlarmTimer(TObject *Sender)
{
    TimerAlarm->Enabled = false;

    String msg = L"Expired @ " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz");
    Memo1->Lines->Add(msg);

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

qiita.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0