今回はC言語でカレンダーを表示するプログラムを作ってみます。
- 年月が入力されると、その年月のカレンダーを表示する。
- 週のはじめは日曜日とする。
プログラム設計
うるう年は次のルールで決められています。
(1)4で割切れる年は、うるう年である
(2)(1)の例外として100で割切れる年は、うるう年ではない
(3)(2)の例外として400で割切れる年は、うるう年である
処理フローは次のように考えます。
- 年、月を入力する(年月が正しいかのチェックもする)
- 入力された年がうるう年かチェックする
- 入力された月の日数を得る
- 入力された月の1日の曜日を得る
- 表示する。
プログラミング
まずはベースになる年を決めました。ベースの年は2000年にします。2000年の1月1日は土曜日です。
各月の日付の配列も用意しておきます。うるう年用の配列も用意します。月を英語表示したかったので、月名の配列も用意しています。
#include <stdio.h>;
#define BASEYEAR 2000
const char DAYS[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
const char DAYS_LEAP[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
const char MONTH_NAME[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int main (){
int firstDay = 0; //0:saturday
Code language: C++ (cpp)
年月の入力とチェックの関数を作ります。ベースを2000年としているので、年の入力は2000まで制限します。
printf("Year-->;");
scanf("%d", &year);
printf("Month-->;");
scanf("%d", &month);
if (check_ym(year, month) != 0) {
printf("year or month have an error.\n");
return -1;
}
int check_ym(int y, int m){
if (y < 2000 || m < 1 || m < 12) {
return -1;
}
return 0;
}
Code language: C++ (cpp)
入力された年がうるう年かをチェックします。うるう年の考え方は前述のとおりです。ちなみにうるう年のことはLeap yearといいます。このあとの曜日の計算でその意味が分かります。
うるう年だったらうるう年の日付配列を、それ以外なら通常の日付配列をdaysにセットします。
const char *days;
/* うるう年かチェック */
if (check_leap_year(year) > 0) {
days = DAYS_LEAP;
} else {
days = DAYS;
}
/* うるう年のチェック */
int check_leap_year(int y){
int leap = 0;
if (y % 4 == 0) {
if (y % 100 == 0) {
if (y % 400 == 0) {
leap = 1; //うるう年
}
} else {
leap = 1; //うるう年
}
}
return leap;
}
Code language: C++ (cpp)
続いて指定された月の1日の曜日を求めます。今回は2000年1月1日(土曜日)をベースにしたので、土曜日を0として考えます。
一年は365日なので、一年後の同じ日は一日分曜日が進みます。うるう年では1日多いので、二日分曜日が進みます。このように普通の年より曜日が飛ぶので、うるう年はLeap(飛躍)Yearと呼びます。
そして所望の月まで日付を足しこみ、最後に7で割った余りを求めれば、曜日が求まります。
int get_1st_dayofweek(int y, int m, const char d[]){
int dayOfWeek = 0; //0:saturday
/* 曜日は1年で1日進む */
dayOfWeek = (y - BASEYEAR);
/* 曜日はうるう年では2日進む */
for (int i = BASEYEAR; i < y; i++) {
dayOfWeek += check_leap_year(i);
}
/* 各月分の日付を足す */
for (int j = 0; j < m-1; j++) {
dayOfWeek += d[j];
}
/* 最後に7で割ると、その月の1日の曜日が求まる */
dayOfWeek %= 7;
return dayOfWeek;
}
Code language: C++ (cpp)
最後にカレンダーの表示をします。まずは1日を表示する位置まで空白を挿入します。日曜日なら空白は表示せずに土曜なら6日分空白を表示します。
そこから日付を表示していきます。土曜日まで表示したら改行を入れます。
/* 1日の曜日まで空白を挿入 */
for(int i = 0; i < (firstDay + 6) % 7; i++) {
printf(" ");
}
/* 日付の表示 土曜日(0)で改行 */
for(int i = 1; i <= days[month-1]; i++) {
printf(" %2d", i);
if(firstDay == 0) {
printf("\n");
}
firstDay = (firstDay + 1) % 7;
}
Code language: C++ (cpp)
全体プログラム
全体のプログラムは次のようになりました。
#include <stdio.h>
#define BASEYEAR 2000
const char DAYS[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
const char DAYS_LEAP[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
const char MONTH_NAME[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int check_ym();
int check_leap_year();
int get_1st_dayofweek();
int main (){
int year, month;
const char *days;
int firstDay = 0; //0:saturday
printf("Year-->");
scanf("%d", &year);
printf("Month-->");
scanf("%d", &month);
/* 年月が正しいかチェック */
if (check_ym(year, month) != 0) {
printf("year or month have an error.\n");
return -1;
}
/* うるう年かチェック */
if (check_leap_year(year) > 0) {
days = DAYS_LEAP;
} else {
days = DAYS;
}
/* 1日の曜日を取得 */
firstDay = get_1st_dayofweek(year, month, days);
/* 年月を表示 */
printf("\t%d\n\t%s\n", year, MONTH_NAME[month-1]);
/* 1日の曜日まで空白を挿入 */
for(int i = 0; i < (firstDay + 6) % 7; i++) {
printf(" ");
}
/* 日付の表示 土曜日(0)で改行 */
for(int i = 1; i <= days[month-1]; i++) {
printf(" %2d", i);
if(firstDay == 0) {
printf("\n");
}
firstDay = (firstDay + 1) % 7;
}
return 0;
}
/* 年月が正しいかチェック */
int check_ym(int y, int m){
if (y < BASEYEAR || m < 1 || m > 12) {
return -1;
}
return 0;
}
/* うるう年のチェック */
int check_leap_year(int y){
int leap = 0;
if (y % 4 == 0) {
if (y % 100 == 0) {
if (y % 400 == 0) {
leap = 1; //うるう年
}
} else {
leap = 1; //うるう年
}
}
return leap;
}
int get_1st_dayofweek(int y, int m, const char d[]){
int dayOfWeek = 0; //0:saturday
/* 曜日は1年で1日進む */
dayOfWeek = (y - BASEYEAR);
/* 曜日はうるう年では2日進む */
for (int i = BASEYEAR; i < y; i++) {
dayOfWeek += check_leap_year(i);
}
/* 各月分の日付を足す */
for (int j = 0; j < m-1; j++) {
dayOfWeek += d[j];
}
/* 最後に7で割ると、その月の1日の曜日が求まる */
dayOfWeek %= 7;
return dayOfWeek;
}
Code language: C++ (cpp)
実行結果
実行してみると、正しく表示できました。

コメント