/****************************************************************************** cal.c Copyright (C) 1995 Sunomono 【解 説】 グレゴリウス暦の一年分を 22 行以内に表示します。その年がグレゴリウ ス暦を採用しているかどうかはチェックしません。表示は 1月 5月  9月 2月 6月 10月 3月 7月 11月 4月 8月 12月 のスタイルになります。 【使い方】 cal [year] year は、表示させたい年です。省略時は現在の年になります。 【 付 】 年月日から曜日を求める Zeller の公式は、奥村晴彦氏の「C言語による 最新アルゴリズム事典」(技術評論社)から引用しました。 【覚え書】 1月、5月、9月の最初の週の日曜日の日付(-5 以上 1 以下の整数)を Zeller の公式を利用して求める。以下、各週の日曜の日付から各行を計 算して出力する。 (付:メールアドレス内の「@」を「◎」に変更した。2005-01-30) ******************************************************************************/ #include #include /* atoi */ #include /* time */ /* 各月の日数 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ int ndays[2][13] = {{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }}; char monthname[13][7] = /* お好きなスタイルをどうぞ :-) */ { "******", "J A N ", "F E B ", "M A R ", "A P R ", "M A Y ", "J U N ", \ "J U L ", "A U G ", "S E P ", "O C T ", "N O V ", "D E C " }; /* { "******", "一月 ", "二月 ", "三月 ", "四月 ", "五月 ", "六月 ", \ "七月 ", "八月 ", "九月 ", "十月 ", "十一月", "十二月" }; */ int zeller(int year, int month, int day); int main(int argc, char* argv[]) { int i, j; int year; int leap; int month[3]; /* 表示の3列に対応 */ int day[3]; /* 表示の3列に対応 */ int lin = 0; /* 画面上の行数 */ if (argc > 1) { /* 年をセット */ year = atoi(argv[1]); } else { time_t now = time(NULL); year = localtime(&now)->tm_year + 1900; } leap = !(year % 4) && ((year % 100) || !(year % 400)); /* うるう年? */ for (i = 0; i < 3; i++) { /* 月と最初の週の日曜日の日にちをセット */ month[i] = 4 * i + 1; day[i] = 1 - zeller(year, month[i], 1); } while ((month[0] <= 4) || (month[1] <= 8) || (month[2] <= 12)) { for (i = 0; i < 3; i++) { if (i != 0) { printf(" "); /* 列の間のスペース */ } switch (lin) { /* 月名表示。力まかせだっ ^^; */ case 1: case 2: case 3: putchar(monthname[month[i]][2 * (lin - 1)]); putchar(monthname[month[i]][2 * (lin - 1) + 1]); break; case 6: case 7: case 8: putchar(monthname[month[i]][2 * (lin - 6)]); putchar(monthname[month[i]][2 * (lin - 6) + 1]); break; case 12: case 13: case 14: putchar(monthname[month[i]][2 * (lin - 12)]); putchar(monthname[month[i]][2 * (lin - 12) + 1]); break; case 17: case 18: case 19: putchar(monthname[month[i]][2 * (lin - 17)]); putchar(monthname[month[i]][2 * (lin - 17) + 1]); break; default: printf(" "); } /* 以下、一週間分の日にちの表示 */ for (j = 0; j < 7; j++) { if ((month[i] <= 4 * (i + 1)) && (day[i] > 0)) { printf(" %2d", day[i]); } else { printf(" "); } if (++day[i] > ndays[leap][month[i]]) { day[i] -= (ndays[leap][month[i]] + 7); month[i]++; } } } lin++; putchar('\n'); } return 0; } /* main() */ /****************************************************************************** 【関数名】 zeller() 【機 能】 引数として与えられた日が何曜日かを返す。0 が日曜日、6 が土曜日。 【引 数】 年、月、日。 【 付 】 奥村晴彦氏の「C言語による最新アルゴリズム事典」(技術評論社)から の引用。 ******************************************************************************/ int zeller(int year, int month, int day) { if (month < 3) { year--; month += 12; } return (year + year / 4 - year / 100 + year / 400 \ + (13 * month + 8) / 5 + day) % 7; } /* zeller() */