時間・時刻を計算する関数 - 情報処理IIレジュメ(9)

仕様

時刻または時間の時・分・秒を整数配列で保持することとする。 例えば、 2 時 34 分 56 秒という時刻であれば、以下のように長さ 3 の整数型の要素を持つ配列を用意するものとする。 ここで、HH、MM、SS などを定数で定義しているのは後で日付などが追加されることなどを考慮したためである。 0, 1, 2 のような意味づけした数値(Magic Number) を使うのではなく、定数にすることにより、データ構造が変化した場合にも柔軟に対応することが可能となる。

#define N 3
#define HH 0
#define MM 1
#define SS 2
(中略)
int jikoku[N];
jikoku[HH] = 2;
jikoku[MM] = 34;
jikoku[SS] = 56;

f:id:hkob:20200608141621p:plain
時刻・時間配列

作成する関数

関数のポンチ絵を記述するので、プロトタイプ宣言を記述すること。

  1. h:m:s の 0:00:00 からの秒数を得る

    f:id:hkob:20200607094441p:plain
    getSeconds

  2. 0:00:00 からの秒数を時刻から得る

    f:id:hkob:20200607095108p:plain
    getSecondsFromTime

  3. 0:00:00 からの秒数から時刻を得る

    f:id:hkob:20200607100033p:plain
    makeTimeFromSeconds

  4. 時刻・時間のセット (結果の分・秒は範囲内に設定されていること。ただし、入力の m, s は 0 か ら 59 までの範囲に入っていない場合もあることを考えること。例 62 分→ 1 時間 2 分に変換でき るように)

    f:id:hkob:20200608155450p:plain
    makeTime

  5. 時刻の前後関係を返す (t1p が t2p より未来なら 1、過去なら −1、等しければ 0)

    f:id:hkob:20200607100726p:plain
    timeCmp

  6. 時刻に時間を加算した時刻を得る (結果の分・秒は範囲内に設定されていること)

    f:id:hkob:20200607100950p:plain
    addTime

  7. 時間を n 倍した時間を得る (分・秒は範囲内に設定されていること)

    f:id:hkob:20200607101241p:plain
    mulTime

  8. 時間を n 等分した時間を得る (端数秒は切り捨て。結果の分・秒は範囲内に設定されていること)

    f:id:hkob:20200607101342p:plain
    divTime

  9. 時間(t1p)を時間(t2p)で割り、何等分できるかを得る(端数は切り捨て)

    f:id:hkob:20200607101453p:plain
    divTimeByTime

  10. 二つの時刻の間の時間を得る(正の値が必要なので未来から過去を引くこと。結果の分・秒は範囲内に設定されていること)

    f:id:hkob:20200607101603p:plain
    subTime

ファイルの準備

時刻・時間の関数を作成する前に、それをテストするためのプログラム(testMyTime.c)を書く。まずは,もっとも簡単な時刻から秒数を得るプログラムのテストを作成する。先週の base フォルダを用いて関係するファイルを用意すること。以下手順を示す。

  • base.zip をダウンロードし、展開する。
  • base という名前を myTime に変更する。
  • このフォルダで iTerm2 または PowerShell を開く。
  • code . として Visual Studio Code を開く。
  • ファイル名を以下のように変更する。
    • _gitignore → .gitignore
    • fact.c → myTime.c
    • fact.h → myTime.h
    • factMain.c → myTimeMain.c
    • testFact.c → testMyTime.c
  • Makefile を開き、上と同じ修正を行う
    • fact.h → myTime.h
    • fact.o → myTime.o
    • factMain → myTimeMain
    • testFact → testMyTime
  • ファイルの準備ができたので、chokidar でファイルを監視する。
chokidar *.c *.h Makefile -c "make test"

テストの作成

testMyTime.c を以下のように記述する。まず最初に getSeconds のテストを記述する。##########の部分は自分で考えること。

#include <stdio.h>

#include "myTime.h"
#include "testCommon.h"

void testGetSeconds() {
    int ans;
    testStart("getSeconds");
    ans = getSeconds(2, 34, 56);
    assertEqualsInt(ans, ##########);
    ans = getSeconds(11, 59, 59);
    assertEqualsInt(ans, ##########);
}

int main() {
    testGetSeconds();
    testErrorCheck();
    return 0;
}
  • 実装の雛形まで作成し,コンパイルできることを確認する。以下のことに気をつけること。
    • 実装は当初中身は適当な return 文のみを書き、コンパイルが通ることだけを確認すること
    • テストは複数個記述すること。 一つだけでは偶然一致してしま うかもしれないからである。
  • テストに失敗することを確認する
  • テストが通過するように実装を記述する
  • 一つの工程が終わったら source をコミットすること

テストの追加 (getSecondsFromTime)

  • getSeconds が通ったら、次の関数 (getSecondsFromTime) をテストする。
// testGetSeconds() の下に記述する
void testGetSecondsFromTime() {
    int jikoku1[N] = {2, 34, 56}, jikoku2[N] = {11, 59, 59};
    int ans;
    testStart("getSecondsFromTime");
    ans = getSecondsFromTime(jikoku1);
    assertEqualsInt(ans, ##########);
    ans = getSecondsFromTime(jikoku2);
    assertEqualsInt(ans, ##########);
}

int main() {
    testGetSeconds();
    testGetSecondsFromTime(); // ここを増やす
    testErrorCheck();
    return 0;
}
  • 実装の雛形まで作成し,コンパイルできることを確認する
  • テストに失敗することを確認する
  • テストが通過するように実装を記述する

更なるテストの追加 (makeTimeFromSeconds)

  • getSecondsFromTime が通ったら、次の関数(makeTimeFromSeconds)をテストする。
// testGetSecondsFromTime() の下に記述する
void testMakeTimeFromSeconds() {
    int jikoku[N];
    testStart("makeTimeFromSeconds");
    makeTimeFromSeconds(jikoku, 2 * 3600 + 34 * 60 + 56);
    assertEqualsInt(jikoku[HH], ###);
    assertEqualsInt(jikoku[MM], ###);
    assertEqualsInt(jikoku[SS], ###);
    makeTimeFromSeconds(jikoku, 12 * 3600 - 1);
    assertEqualsInt(jikoku[HH], ###);
    assertEqualsInt(jikoku[MM], ###);
    assertEqualsInt(jikoku[SS], ###);
}

int main() {
    testGetSeconds();
    testGetSecondsFromTime();
    testMakeTimeFromSeconds(); // ここを増やす
    testErrorCheck();
    return 0;
}
  • 実装の雛形まで作成し,コンパイルできることを確認する
  • テストに失敗することを確認する
  • テストが通過するように実装を記述する

hkob.hatenablog.com