mk-mode BLOG

このブログは自作の自宅サーバに構築した Debian GNU/Linux で運用しています。
PC・サーバ構築等の話題を中心に公開しております。(クローンサイト: GitHub Pages

ブログ開設日2009-01-05
サーバ連続稼働時間
Reading...
Page View 合計
Reading...
今日
Reading...
昨日
Reading...

C++ - 日付妥当性チェック!

[ プログラミング ] [ C++ ]

こんばんは。

日付の妥当性をチェックする C++ コードです。

0. 前提条件

  • LMDE2 (Linux Mint Debian Edition 2) での作業を想定。
  • g++ 4.9.2 でのコンパイルを想定。
  • チェックは8桁数字で行うので、チェック可能範囲は西暦0年1月1日〜西暦9999年12月31日。
  • 当方、 C++ に長けていないので、綺麗なコーディングではないかもしれない。

1. C++ コードの作成

簡単なソースコードなので1ファイルで作成してもよかったが、今後部品として再利用することも考慮してヘッダ・ソース・実行ファイルに分割している。

【ヘッダファイル】

validation.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * @file   validation.hpp
 * @briaf  Validation クラス用ヘッダファイル
 *
 * @date   2017-01-09 新規作成
 * @author mk-mode.com
 */
#ifndef INCLUDED_VALIDATION_HPP
#define INCLUDED_VALIDATION_HPP
#include <string>

/**
 * @class Validation
 * @brief 妥当性チェッククラス
 */
class Validation
{
    static const int DAYS_IN_MONTH[];
    std::string date, year, month, day;
    bool isLeapYear(int);
    int  daysInMonth(int, int);
    bool isDigit();

public:
    Validation(std::string);  // コンストラクタ
    bool isValid();           // 妥当性チェック
};
#endif

【ソースファイル】

validation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
 * @file   validation.cpp
 * @briaf  Validation クラス
 *
 * @date   2017-01-09 新規作成
 * @author mk-mode.com
 */
#include <cstdlib>
#include <iostream>
#include <string>
#include <ctype.h>
#include "validation.hpp"

using namespace std;

/**
 * @brief 定数(月内日数)
 */
const int Validation::DAYS_IN_MONTH[] = {
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

/**
 * @brief     コンストラクタ
 *
 * @param[in] 日付(string; YYYYMMDD形式)
 * @return    <none>
 */
Validation::Validation(string date)
{
    this->date  = date;
    this->year  = date.substr(0, 4);
    this->month = date.substr(4, 2);
    this->day   = date.substr(6, 2);
}

/**
 * @brief     数字チェック
 *
 * @param[in] <none>
 * @return    真偽
 * @retval    true  数字
 * @retval    false 数字以外あり
 */
bool Validation::isDigit()
{
    unsigned int i;
    for (i = 0; i < year.length(); i++)
        if (isdigit(year[i]) == 0) return false;
    for (i = 0; i < month.length(); i++)
        if (isdigit(month[i]) == 0) return false;
    for (i = 0; i < day.length(); i++)
        if (isdigit(day[i]) == 0) return false;
    return true;
}

/**
 * @brief     うるう年チェック
 *
 * @param[in] 年(int)
 * @return    真偽
 * @retval    true  うるう年
 * @retval    false 平年
 */
bool Validation::isLeapYear(int y)
{
    return (y % 400 == 0) || ((y % 4 == 0) && (y % 100 != 0));
}

/**
 * @brief     月内日数取得
 *
 * @param[in] 年(int)
 * @param[in] 月(int)
 * @return    月内日数(int)
 */
int Validation::daysInMonth(int y, int m)
{
    if (m < 1 || 12 < m) return 0;
    if (m == 2 && isLeapYear(y) == true) return 29;
    return DAYS_IN_MONTH[m - 1];
}

/**
 * @brief     日付妥当性チェック
 *
 * @param[in] <none>
 * @return    真偽
 * @retval    true  妥当
 * @retval    false 不当
 */
bool Validation::isValid()
{
    int y = atoi(year.c_str());
    int m = atoi(month.c_str());
    int d = atoi(day.c_str());
    if (!isDigit()) return false;
    if (m < 1 || m > 12 || d < 1 || d > daysInMonth(y, m)) return false;
    return true;  // Valid
}

【実行ファイル】

date_validation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * @file   date_validation.cpp
 * @briaf  日付妥当性チェック
 *
 * @date   2017-01-09 新規作成
 * @author mk-mode.com
 */
// コマンドライン引数: YYYYMMDD
#include <iostream>
#include "validation.hpp"

using namespace std;

/**
 * @brief     メイン処理
 *
 * @param[in] argc 引数の数
 * @param[in] argv 引数の値の配列
 * @return    return code
 * @retval    0 正常終了
 * @retval    1 異常終了
 */
int main(int argc, char* argv[])
{
    string date;

    try {
        // コマンドライン引数取得
        if (argc < 2) {
            cout << "Please input in the format of YYYYMMDD." << endl;
            return 1;
        }
        date = argv[1];
        cout << date << ": ";

        // コマンドライン引数の長さチェック
        if (date.length() != 8) {
            cout << "Invalid!" << endl;
            return 1;
        }

        // 日付妥当性チェック
        Validation objValid(date);
        if (!objValid.isValid()) {
            cout << "Invalid!" << endl;
            return 1;
        }
    }
    catch (...) {
        cout << "EXCEPTION!" << endl;
        return 1;
    }

    // Not invalid
    cout << "Valid!" << endl;
    return 0;
}

2. コンパイル

1
$ g++ -Wall -O2 date_validation.cpp validation.cpp -o date_validation

もしくは、

1
2
3
$ g++ -Wall -O2 -c validation.cpp -o validation.o
$ g++ -Wall -O2 -c date_validation.cpp -o date_validation.o
$ g++ -Wall -O2 date_validation.o validation.o -o date_validation

3. 実行

日付を YYYYMMDD の書式でコマンドライン引数に指定して実行する。

コマンドライン引数が8桁でなかったり、数字以外が含まれていたり、妥当な日付でない場合は Invalid! と出力する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ ./date_validation 20170228
20170228: Valid!

$ ./date_validation 20000229
20000229: Valid!

$ ./date_validation 20170229
20170229: Invalid!

$ ./date_validation 21000229
21000229: Invalid!

$ ./date_validation 20170000
20170000: Invalid!

$ ./date_validation 20171232
20171232: Invalid!

$ ./date_validation 201701234
201701234: Invalid!

$ ./date_validation 2017063a
2017063a: Invalid!

あちこちで利用できるでしょう。

以上。

Comments