0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カレンダープログラム

Last updated at Posted at 2025-12-20

目的

ある月のカレンダーを表示させるプログラムを実装する。

仕様

  • 日本でグレゴリオ暦が正式採用された1873年1月1日以降(明治6年)の日付を計算する
  • ひと月単位のカレンダーを表示するためには1日の曜日を求める必要がある
  • 2000/1/1(土曜日)を基準としてカレンダーにしたい月の1日の曜日を計算する
    • 2000年以降はそこから曜日を求めたい日付まで何日経過したか
    • 1999年以前はそこから何日遡るか
    • つまり基準日から着目する日付までの日数から曜日を計算する

ソースコード

#include <stdio.h>

// 閏年判定関数
// 4で割り切れてかつ100で割り切れない、または400で割り切れる年は閏年
int isLeapYear(int year){
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 引数の日付の曜日を計算する
// 戻り値は曜日番号 0:Sunday, 1:Monday, 2:Tuesday, 3:Wednesday, 4:Thursday, 5:Friday, 6:Saturday
// -> 2000/1/1からの日数を計算することにより曜日番号を求める
// (c.f. 2000/1/1 Saturday)
int calcDayOfWeek(int year, int month, int day){

    int y, m;
    // 基準とする2000/1/1からの日数
    int totalDays = 0;
    // 曜日番号 0:Sunday, 1:Monday, 2:Tuesday, 3:Wednesday, 4:Thursday, 5:Friday, 6:Saturday
    int dayOfWeekNum;
    // 各月の日数(平年), 月と要素番号を合わせるために0番目に0を格納する
    int daysInMonth[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};

    if(year < 2000){
    // 1999年以前のカレンダーを計算する場合
    // この場合は1999/12/31から求める日付まで遡るように計算する
    // 例として1990/5/5の曜日を求める場合を考える

        // 1999~1991までの日数を足す
        for(y = 1999; y > year; y--){
            // 閏年ならば1年366日を足す
            if (isLeapYear(y)){
                totalDays += 366;
            }else{
                totalDays += 365;
            }
        }

        // yearが閏年なら2月を29日に設定する
        if (isLeapYear(year)) daysInMonth[2] = 29;
        // 1990年の12月から6月までの日数の合計を求める
        for(m = 12; m > month; m--){
        totalDays += daysInMonth[m];
        }
        // 5月末から5/5までの日数を加える
        totalDays += daysInMonth[month] - day + 1;

        dayOfWeekNum = 6 - totalDays%7;
    
    }else{
    // 2000年以降のカレンダーを計算する場合
    // 2000/1/1
        for(y = 2000; y < year; y++){
            // yが閏年ならば1年366日を足す
            if (isLeapYear(y)){
                totalDays += 366;
            }else{
                totalDays += 365;
            }
        }

        // yearが閏年なら2月を29日に設定する
        if (isLeapYear(year)) daysInMonth[2] = 29;
        for(m = 1; m < month; m++){
            totalDays += daysInMonth[m];
        }
        totalDays += day - 1;

        // 基準日である2000/1/1の曜日番号も足す
        totalDays += 6;
        dayOfWeekNum = totalDays%7;
    }
    
    return (dayOfWeekNum);

}

int main(void){

    int year, month;

    // 年の入力
    printf("年を入力: ");
    scanf("%d", &year);
    // 月の入力
    printf("月を入力: ");
    scanf("%d", &month);
    
    if(year < 1873){
        printf("Only compatible from 1873.\n");
        return(0);
    }
    if(month < 1 || 12 < month){
        printf("input the month in 1-12.\n");
        return(0);
    }

    // 各月の日数(平年), 月と要素番号を合わせるために0番目に0を格納する
    int daysInMonth[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    // yearが閏年なら2月を29日に設定する
    if (month == 2 && isLeapYear(year)) daysInMonth[2] = 29;

    // カレンダーの見出し
    printf("\n%d年 %d月のカレンダー\n", year, month);
    printf("日 月 火 水 木 金 土\n");

    // 指定月の1日が何曜日かを計算する
    int firstDay = calcDayOfWeek(year, month, 1);

    // カレンダー最初の行に空白を出力
    for (int i = 0; i < firstDay; i++) {
        printf("   "); // 空白3文字分
    }

    // 各日の出力
    for (int day = 1; day <= daysInMonth[month]; day++) {
        printf("%2d ", day);    // 2桁表示で揃える

        // 土曜ごとに改行
        if ((firstDay + day) % 7 == 0) printf("\n");
    }

    printf("\n"); // 最後に改行
    return(0);
}

出力結果


年を入力: 2026
月を入力: 1

2026年 1月のカレンダー
日 月 火 水 木 金 土
             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 


年を入力: 1990
月を入力: 5

1990年 5月のカレンダー
日 月 火 水 木 金 土
       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 

課題

  • 各月の日数を格納した配列daysInMonth[]が二度定義されている(main関数とcalcDayOfWeek関数)
    • 入力した月の日数を返す関数を新規に作成することで解決
  • isLeapYear関数は閏年か否や(true/false)をreturnするため、呼び出し元でその戻り値に基づいて着目している年が365日なのか366日なのかを割り振らないといけない(二度手間なプロセス)
    • ある年が閏年 or Notではなく、365日あるいは366日なのかを返す関数にしたい
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?