Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

【C言語】日付が有効かどうかを判定するプログラムの書き方

本記事では、年・月・日を整数として受け取り、その日付が実際に存在しうるものかどうかを判定するC言語のプログラムを解説します。

ここで「有効な日付」とは、1800年1月1日〜9999年12月31日の範囲に含まれ、カレンダー上のあらゆる制約(月ごとの日数や閏年のルールなど)を満たす日付のことを指します。この範囲外の日付はすべて無効として扱います。

有効な日付の条件

日付が有効であるためには、以下の制約をすべて満たす必要があります。

  • 日は1以上31以下であること
  • 月は1以上12以下であること
  • 年は1800以上9999以下であること
  • 4月・6月・9月・11月の場合、日は30以下であること
  • 2月の場合は、次のように閏年かどうかで判定が変わる
    • 閏年であれば、日は29以下であること
    • 平年であれば、日は28以下であること

これらの条件がすべて成立すれば有効な日付、一つでも満たさなければ無効な日付と判断します。

実行例

入力:y = 2002, d = 29, m = 11
出力:Date is valid(日付は有効)

入力:y = 2001, d = 29, m = 2
出力:date is not valid(日付は無効)

1つ目の例では、11月は30日まである月のため、29日は有効です。2つ目の例では、2001年は閏年ではないため、2月29日は存在せず無効になります。

アルゴリズム

処理の流れは以下の通りです。

  1. isleap関数: 西暦年yを受け取り、閏年であれば1、そうでなければ0を返す。
    閏年の判定は「4で割り切れ、かつ100で割り切れない年」または「400で割り切れる年」です。
  2. datevalid関数: 日(d)、月(m)、年(y)を受け取り、以下の順で検証する。
    1. 年が min_yr(1800)〜max_yr(9999) の範囲外なら0を返す
    2. 月が1〜12の範囲外なら0を返す
    3. 日が1〜31の範囲外なら0を返す
    4. 月が2月の場合、isleap(y)の結果に応じて日が29以下(閏年)または28以下(平年)かを確認し、条件を満たせば1、満たさなければ0を返す
    5. 月が4・6・9・11の場合、日が30以下なら1、そうでなければ0を返す
    6. いずれの条件にも該当しなければ、その月は31日まである月なので1を返す
  3. main関数: 年・月・日の値を設定し、datevalid関数の戻り値に応じて結果を出力する。

C言語による実装例

#include <stdio.h>
#define max_yr 9999
#define min_yr 1800

// 閏年かどうかを判定する(閏年なら1を返す)
int isleap(int y) {
    if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
        return 1;
    else
        return 0;
}

// 日付の妥当性をチェックする関数
int datevalid(int d, int m, int y) {
    // 年の範囲チェック
    if (y < min_yr || y > max_yr)
        return 0;
    // 月の範囲チェック
    if (m < 1 || m > 12)
        return 0;
    // 日の範囲チェック
    if (d < 1 || d > 31)
        return 0;

    // 月ごとの日数をチェック
    if (m == 2) {
        if (isleap(y)) {
            if (d <= 29)
                return 1;
            else
                return 0;
        } else {
            if (d <= 28)
                return 1;
            else
                return 0;
        }
    }

    // 4月・6月・9月・11月は30日まで
    if (m == 4 || m == 6 || m == 9 || m == 11) {
        if (d <= 30)
            return 1;
        else
            return 0;
    }

    // 残りの月は31日まで
    return 1;
}

int main(void) {
    int y = 2002;
    int d = 29;
    int m = 11;

    if (datevalid(d, m, y))
        printf("Date is valid\n");
    else
        printf("Date is not valid\n");

    return 0;
}

出力結果

上記のコードを実行すると、次の出力が得られます。

Date is valid

補足:閏年の判定ルールについて

グレゴリオ暦における閏年の正確なルールは以下の3段階です。

  • 4で割り切れる年は閏年候補
  • ただし100で割り切れる年は平年
  • さらに400で割り切れる年は閏年(例:2000年は閏年、1900年は平年)

このルールを論理式で表すと (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) となります。単純に「4で割り切れる年をすべて閏年とする」実装では、1900年のような世紀の境目で誤判定が発生するため注意が必要です。また、2月の判定では閏年でない場合に28日以下かどうかのチェックを行う分岐を必ず入れることで、平年の2月29日などを確実に弾けるようになります。

  1. 【C言語】再帰を使って配列が回文かどうかを判定するプログラム

    配列 arr[n](n は配列のサイズ)が与えられたとき、再帰を用いてその配列が回文かどうかを判定するのが本記事のテーマです。回文とは、前から読んでも後ろから読んでも同じになる並びのことで、「MADAM」や「NAMAN」などが代表的な例です。配列が回文かどうかを調べるには、先頭と末尾から順に要素を比較していきます。再帰的なアプローチでも同様に、start と end の値を更新しながら比較を続けます。start と end が交差(すれ違う)すれば回文と判定でき、途中で要素が一致しなかった場合はそこで処理を打ち切り、false を返します。入力例と出力例入力: arr[] = { 2, 3,

  2. C言語で配列が回文かどうかを判定するプログラム

    回文とは任意のサイズ n の配列 arr[] が与えられたとき、その配列が回文(パリンドローム)かどうかを判定するのが本記事の目的です。回文とは、前から読んでも後ろから読んでも同じになる並びのことで、MADAM や NAMAN といった文字列が代表的な例として挙げられます。配列が回文かどうかを確認するには、配列を先頭からと末尾から同時に走査し、対応する要素同士を比較していきます。入力例と出力例Input: arr[] = {1, 0, 0, 1} Output: 配列は回文です Input: arr[] = {1, 2, 3, 4, 5} Output: 配列は回文ではありません考え方(アプ