debug
DependencyInjection
cppBuilder
timerEvent
#migrated

C++ Builder > TTimer > 指定時刻(hh, mm)に処理をする (毎日処理) > TTimer(1秒)+期限更新 | Dependency Injectionを使ったテスト

動作環境
C++ Builder XE4

前回: https://qiita.com/7of9/items/b473ad1d0e1a24f40d27

処理概要

  • 指定時刻(hh, mm)に処理を行う
  • 毎日処理をする

  • v0.1

    • 実装したが、1日一回の処理を待つわけにはいかない
  • v0.2

    • Dependency Injectionを使って「現在日時」の(時、分、秒)を変更するボタン3つを追加
      • => ボタンをN回押して調整するのが面倒
  • v0.3

    • TDateTimePickerを使った
    • 「現在日時」をTDateTimePickerのDate,Timeで置き換え

コンポーネント概要

  • Timer1sec : 1秒ごとのタイマー
    • 「現在日時」の表示更新
    • 「次の処理日時」に達したか確認する
  • m_nextDateTime: 次の処理日時
  • m_nowDateTime: 現在日時
    • getNow()で使われる
  • TimerAddSecond: 1秒ごとのタイマー
    • m_nowDateTimeを毎秒更新する

code v0.1..v0.3

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>
#include <Vcl.ComCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
    TTimer *Timer1sec;
    TEdit *E_hh;
    TEdit *E_mm;
    TLabel *Label1;
    TButton *B_start;
    TMemo *Memo1;
    TTimer *TimerAddSecond;
    TButton *dbgB_add5Sec;
    TLabel *L_nowDateTime;
    TButton *dbgB_addHour;
    TButton *dbgB_add5Min;
    TDateTimePicker *DTP_time;
    TDateTimePicker *DTP_date;
    TButton *dbgB_setDateTime;
    void __fastcall Timer1secTimer(TObject *Sender);
    void __fastcall B_startClick(TObject *Sender);
    void __fastcall TimerAddSecondTimer(TObject *Sender);
    void __fastcall dbgB_add5SecClick(TObject *Sender);
    void __fastcall dbgB_addHourClick(TObject *Sender);
    void __fastcall dbgB_add5MinClick(TObject *Sender);
    void __fastcall dbgB_setDateTimeClick(TObject *Sender);
private:    // ユーザー宣言
    TDateTime m_nowDateTime; // 現在時刻 (Dependency Injection用)
    TDateTime m_nextDateTime; // 次の処理時間
    TDateTime __fastcall getNextAlarmDateTime(TDateTime now, int hh, int mm);
    TDateTime __fastcall getNow(void);
public:     // ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.dfm
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 300
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 35
    Width = 179
    Height = 13
    Caption = '                               h                        m'
  end
  object L_nowDateTime: TLabel
    Left = 8
    Top = 8
    Width = 92
    Height = 16
    Caption = 'L_nowDateTime'
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Tahoma'
    Font.Style = []
    ParentFont = False
  end
  object E_hh: TEdit
    Left = 40
    Top = 32
    Width = 57
    Height = 21
    TabOrder = 0
    Text = '10'
  end
  object E_mm: TEdit
    Left = 120
    Top = 32
    Width = 57
    Height = 21
    TabOrder = 1
    Text = '30'
  end
  object B_start: TButton
    Left = 216
    Top = 30
    Width = 75
    Height = 25
    Caption = 'B_start'
    TabOrder = 2
    OnClick = B_startClick
  end
  object Memo1: TMemo
    Left = 8
    Top = 104
    Width = 617
    Height = 185
    Lines.Strings = (
      'Memo1')
    ScrollBars = ssVertical
    TabOrder = 3
  end
  object dbgB_add5Sec: TButton
    Left = 320
    Top = 8
    Width = 75
    Height = 25
    Caption = 'dbgB_add5Sec'
    TabOrder = 4
    OnClick = dbgB_add5SecClick
  end
  object dbgB_addHour: TButton
    Left = 320
    Top = 73
    Width = 75
    Height = 25
    Caption = 'dbgB_addHour'
    TabOrder = 5
    OnClick = dbgB_addHourClick
  end
  object dbgB_add5Min: TButton
    Left = 320
    Top = 42
    Width = 75
    Height = 25
    Caption = 'dbgB_add5Min'
    TabOrder = 6
    OnClick = dbgB_add5MinClick
  end
  object DTP_time: TDateTimePicker
    Left = 440
    Top = 35
    Width = 81
    Height = 21
    Date = 43026.485760914350000000
    Time = 43026.485760914350000000
    Kind = dtkTime
    TabOrder = 7
  end
  object DTP_date: TDateTimePicker
    Left = 440
    Top = 8
    Width = 97
    Height = 21
    Date = 43026.488268506950000000
    Time = 43026.488268506950000000
    TabOrder = 8
  end
  object dbgB_setDateTime: TButton
    Left = 440
    Top = 62
    Width = 75
    Height = 25
    Caption = 'dbgB_setDateTime'
    TabOrder = 9
    OnClick = dbgB_setDateTimeClick
  end
  object Timer1sec: TTimer
    OnTimer = Timer1secTimer
    Left = 88
    Top = 64
  end
  object TimerAddSecond: TTimer
    OnTimer = TimerAddSecondTimer
    Left = 136
    Top = 64
  end
end

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.3 Oct. 18, 2017 Improve debug feature
    - add [dbgB_setDateTime]
    - add [DTP_time]
    - add [DTP_date]
v0.2 Oct. 18, 2017 Dependency Injection for Now()
    - add debug
        + add [dbgB_addHour]
        + add [dbgB_add5Min]
        + add [dbgB_add5Sec]
    - add getNow()
    - add [m_nowDateTime]
v0.1 Oct. 18, 2017
    - add [kInit_dateTime]
    - add getNextAlarmDateTime()
    - add [m_nextDateTime]
*/

static const TDateTime kInit_dateTime = (TDateTime)0;

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    m_nextDateTime = kInit_dateTime; // @ctor
    m_nowDateTime = Now(); // @ ctor
}
//---------------------------------------------------------------------------

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;
}

TDateTime __fastcall TForm1::getNow(void)
{
    return m_nowDateTime;
    //return Now();
}

void __fastcall TForm1::Timer1secTimer(TObject *Sender)
{
    L_nowDateTime->Caption = getNow().FormatString(L"yyyy/mm/dd hh:nn:ss");

    if (m_nextDateTime == kInit_dateTime) {
        return;
    }
    if (getNow() > m_nextDateTime) {
        m_nextDateTime = IncDay(m_nextDateTime, 1);

        String msg = L"Expired @ " + getNow().DateTimeString();
        Memo1->Lines->Add(msg);
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::B_startClick(TObject *Sender)
{
    // TODO: 0m > 関数化

    // 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. 次の日時取得
    m_nextDateTime = getNextAlarmDateTime(Now(), next_hh, next_mm);

    String msg = "now: " + getNow().DateTimeString() + L" next: " + m_nextDateTime.DateTimeString();
    Memo1->Lines->Add(msg);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerAddSecondTimer(TObject *Sender)
{
    m_nowDateTime = IncSecond(m_nowDateTime, 1);
}
//---------------------------------------------------------------------------
// デバッグ用
void __fastcall TForm1::dbgB_add5SecClick(TObject *Sender)
{
    m_nowDateTime = IncSecond(m_nowDateTime, 5);
}
void __fastcall TForm1::dbgB_add5MinClick(TObject *Sender)
{
    m_nowDateTime = IncMinute(m_nowDateTime, 5);
}
void __fastcall TForm1::dbgB_addHourClick(TObject *Sender)
{
    m_nowDateTime = IncHour(m_nowDateTime, 1);
}
void __fastcall TForm1::dbgB_setDateTimeClick(TObject *Sender)
{
    m_nowDateTime = DateOf(DTP_date->Date) + TimeOf(DTP_time->Time);
}
//---------------------------------------------------------------------------

結果

Expired が発生した後にTDateTimePickerの日時を次の発生日時の前に変更してdbgB_setDateTimeを押す、ということを繰り返した。
以下となり、実装としては正しそう。

qiita.png

追記

(2017/10/23)

StrToIntDef()にてtry, catchをしているが、try, catchは不要のように思う。