C言語でのカレンダーの表示について質問です
VisualStudioを使ってC言語でコンソールアプリケーションのカレンダーを作っています。
やりたいことは以下の通りです。
プログラムを起動すると、現在の月を中央に三ヶ月分のカレンダーを表示。
Lキーでカレンダー全体を一ヶ月前に変更
Rキーで一ヶ月後に変更
Dキーで三ヶ月前に変更
Uキーで三ヶ月後に変更
Aキーで一年前に変更
Bキーで一年後に変更
起動時にカレンダー表示するのはできているんですが、Rでカレンダーを進めていくと12月の次が13月、次が0月、その次が1月となってしまい、日付も上手いこと表示されません。
L,D,U,でも同じようになります。
また、A,Bで年を変えると日付が正確に表示されないです。
これらを正しく表示させる方法をご教授いただけますでしょうか。
#include <stdio.h>
#include <conio.h>
#include <time.h>
#define KEY_ESC (0x1b) // エスケープ
#define KEY_L (0x6c) // L
#define KEY_D (0x64) // D
#define KEY_R (0x72) // R
#define KEY_U (0x75) // U
#define KEY_A (0x61) // A
#define KEY_B (0x62) // B
time_t timer; // 現在の時刻
struct tm local; // 地方時
int curr_year; // 現在の年
int curr_mon; // 現在の月
int input; // どのキーが入力されたか
int calendar[12][6][7]; // 月、最大の週、1週間
int year; // 年
int month; // 月
int day; // 日
int nweek; // その月が何周あるか
int nday; // その月が何日まであるか
int day_of_week; // その月が何曜日から始まるか
void CalendarDisplay(void);
void CalendarSet(void);
void DayOfWeek(int, int, int);
void NumOfDay(int);
void KeyOperat(int);
int LaepYear(int, int);
int Zeller(int, int, int);
int main(void)
{
CalendarDisplay();
while (1)
{
printf("ESCキーで終了\n\n");
input = _getch();
if(input == KEY_ESC) {
break;
}
else if(input == KEY_L || input == KEY_D ||
input == KEY_R || input == KEY_U ||
input == KEY_A || input == KEY_B) {
KeyOperat(input);
}
}
return 0;
}
// カレンダーの表示
void CalendarDisplay(void)
{
// 現在時刻を取得
timer = time(NULL);
// 地方時に変換
localtime_s(&local, &timer);
// 現在の年
curr_year = local.tm_year + 1900;
// 現在の月
curr_mon = local.tm_mon + 1;
CalendarSet();
}
// 当月とその±1の月を設定
void CalendarSet(void)
{
for (month = curr_mon-1; month <= curr_mon+1; month++)
{
// 12月を超えたら次の年に
if(curr_mon > 12) {
curr_mon = 1;
month = 1;
curr_year += 1;
}
// 1月を超えたら前の年に
else if(curr_mon < 1) {
curr_mon = 12;
month = 12;
curr_year -= 1;
}
// その月が何日まであるか求めて代入
nday = LaepYear(curr_year, month);
// その月が何曜日から始まるか
day_of_week = Zeller(curr_year, month, 1);
nweek = 0;
for (day = 1; day <= nday; day++)
{
calendar[month-1][nweek][day_of_week] = day;
//printf("day-> %d ", day);
if (++day_of_week == 7) {
day_of_week = 0;
nweek++;
}
}
}
DayOfWeek(month, curr_mon, curr_year);
}
// 月と曜日の表示
void DayOfWeek(int m, int cur_m, int cur_y)
{
for (m = cur_m-1; m <= cur_m-1; m++)
{
printf("%d%6d月%16d%6d月%16d%6d月\n" "日 月 火 水 木 金 土 "
"日 月 火 水 木 金 土 " "日 月 火 水 木 金 土\n",
cur_y, m, cur_y, m + 1, cur_y, m + 2);
NumOfDay(&calendar[m-1]);
}
}
// 日数の表示
void NumOfDay(int calendar[][6][7])
{
int max_w = 0, nmon = 0, w = 0;
// その月の最大週の間
for (max_w = 0; max_w < 6; max_w++)
{
// 3ヶ月分表示
for (nmon = 0; nmon < 3; nmon++)
{
for (w = 0; w < 7; w++)
{
if (calendar[nmon][max_w][w]) {
printf("%2d ", calendar[nmon][max_w][w]);
}
else {
printf(" ");
}
}
printf(" ");
}
printf("\n");
}
}
// キー操作でカレンダーの表示を変える
void KeyOperat(int input)
{
do {
switch(input)
{
case KEY_L:
curr_mon -= 1;
break;
case KEY_R:
curr_mon += 1;
break;
case KEY_D:
curr_mon -= 3;
break;
case KEY_U:
curr_mon += 3;
break;
case KEY_A:
curr_year -= 1;
break;
case KEY_B:
curr_year += 1;
break;
default :
input = !input;
break;
}
} while(!input);
CalendarSet();
}
// うるう年の判定
int LaepYear(int y, int m)
{
const int num_day[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (m == 2 && y % 4 == 0 &&
(y % 100 != 0 || y % 400 == 0)) {
return 29;
}
return num_day[m - 1];
}
// ツェラーの公式から曜日を求める
int Zeller(int y, int m, int d)
{
int dow;
// 1月と2月の場合、それぞれ前年の13月、14月とする
if(m == 1 || m == 2) {
y--;
m = m + 12;
}
dow = (y + y/4 - y/100 + y/400 + (13*m+8)/5 + d) % 7;
return dow;
}