カレンダー作成プログラム



[ 簡単な説明 ]

出力例は、

     calen   97   1

とした例です。なお、プログラム中では、エスケープ・シーケンスを用いて文字に色をつけています。
出力にタイトル(年月)を付けたり、曜日を表示したり、と改良する余地があります。


プログラム・ソース("calen.c")           top (トップに戻る)
/*		calen.c		*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define		YES		1
#define		NO		0
#define		OK		1
#define		NG		0

#define		number_of_horidays		20

struct tm
{
	int tm_sec;		/* 秒 - [0,59] */
	int tm_min;		/* 分 - [0,59] */
	int tm_hour;	/* 時 - [0,23] */
	int tm_mday;	/* 日 - [1,31] */
	int tm_mon;		/* 月 - [0,11] */
	int tm_year;	/* 年(年-1900) */
	int tm_wday;	/* 曜日 - [0,6] */
	int tm_yday;	/* 通算日 - [0,365] */
	int tm_isdst;	/* 夏時間調整フラグ */
};

int leapyear(int yy);
long _mjd(struct tm *date);
void _jdate(long mjd, struct tm *date);
int _holiday(struct tm *date);
long daycount(struct tm *from, struct tm *to);

struct tm date;

/*--------------------------------------*/
/*		曜日エリア						*/
/*--------------------------------------*/
char *_wday[7] = {"日","月","火","水","木","金","土"};
/*--------------------------------------*/
/*		月の末日エリア					*/
/*--------------------------------------*/
int _mday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*--------------------------------------*/
/*		祝日エリア(振替休日を考慮)	*/
/*--------------------------------------*/
static int _holytbl1[number_of_horidays] = 
{ 101, 115, 211, 429, 503, 504, 505, 720,
  915, 923,1010,1103,1123,1223, 0};
/*--------------------------------------*/
/*		休日エリア(その他の休日)		*/
/*--------------------------------------*/
static int _horiday_table_read = NO;
static int _holytbl2[number_of_horidays] = {0};

/*--------------------------------------*/
/*	閏年判定 (YES:閏年, NO:閏年でない)	*/
/*--------------------------------------*/
int leapyear(int yy)
{
	if((yy % 400) == 0)	return YES;
	if((yy % 100) == 0)	return NO;
	if((yy % 4) == 0)	return YES;
	return NO;
}
/*--------------------------------------*/
/*		準ユリウス日(MJD)の計算	*/
/*--------------------------------------*/
long _mjd(struct tm *date)
{
	long mjd;
	int y, m, d;
			/*   月 = 3   4   5   6   7   8   9  10  11  12   1   2 */
			/*    m = 0   1   2   3   4   5   6   7   8   9  10  11 */
	static yday[] = { 0, 31, 61, 92,122,153,184,214,245,275,306,337};

	if((*date).tm_mon >= 2)
	{
		d = date->tm_mday;
		m = date->tm_mon - 2;
		y = date->tm_year;
		date->tm_yday = 59 + leapyear(1900 + y) + yday[m] + d;
	}
	else
	{
		d = date->tm_mday;
		m = date->tm_mon + 10;
		y = date->tm_year - 1;
		date->tm_yday = date->tm_mon * 31 + d;
	}
	y += 1900;
	mjd = 365L * y + y / 4 - y / 100 + y / 400 + yday[m] + d - 678882L;
	date->tm_wday = (int)((mjd - 4) % 7);
	return mjd;
}
/*--------------------------------------*/
/*		MJDから年月日を計算			*/
/*--------------------------------------*/
void _jdate(long mjd, struct tm *date)
{
	int y, i, j;
	long mjd1, mjd2;

	mjd1 = mjd + 678882L;
	y = (int)(mjd1 / 365 - 2);
	for(;;)
	{
		mjd2 = y * 365L + y / 4 - y / 100 + y / 400 + 306;
		if(mjd2 < mjd1) break;
		y--;
	}
	y++;
	date->tm_year = y - 1900;
	date->tm_mon = 0;				/* 1月 */
	date->tm_mday = 0;				/* 0日 */
	j = (int)(mjd - _mjd(date));

	_mday[1] = 28 + leapyear(y);
	for(i = 0; i < 12; i++)
	{
		j -= _mday[i];
		if(j <= 0)
		{
			j += _mday[i];
			break;
		}
	}
	date->tm_mon = i;
	date->tm_mday = j;
}
/*--------------------------------------*/
/*			休日判定					*/
/*		( 0:休日でない 1:指定休日		*/
/*		  2:祝祭日&振替休日 )			*/
/*--------------------------------------*/
int _holiday(struct tm *date)
{
	int day, i, j;
	FILE *fp;

	if(_horiday_table_read == NO)
	{
		fp = fopen("horiday.tbl", "r");
		if(fp != NULL)
		{
			for(i = 0, j = 1; i < 20 && j == 1; i++)
				j = fscanf(fp, "%d", &(_holytbl2[i]));
			fclose(fp);
		}
		_horiday_table_read = YES;
	}

	i = date->tm_mon + 1;
	day = i * 100 + date->tm_mday;
	for(i = 0; i < number_of_horidays && day >= _holytbl1[i]; i++)
		if(day == _holytbl1[i])	return 2;
	for(i = 0; i < number_of_horidays && day >= _holytbl2[i]; i++)
		if(day == _holytbl2[i])	return 1;

	_mjd(date);
	if(date->tm_wday == 1)					/* 振替休日 */
	{
		if(date->tm_mday != 1)	day -= 1;	/* 前日を計算 */
		else
		{
			i = date->tm_mon;
			day = i * 100 + _mday[i-1];
		}
		for(i = 0; i < number_of_horidays && day >= _holytbl1[i]; i++)
			if(day == _holytbl1[i])	return 2;
	}
	return NO;
}
/*--------------------------------------*/
/*			日数計算					*/
/*--------------------------------------*/
long daycount(struct tm *from, struct tm *to)
{
	long days;

	days = _mjd(to) - _mjd(from);
	if(days >= 0)	return days + 1L;

	return days - 1L;
}

/*--------------------------------------*/
/*		カレンダ作成:メイン関数		*/
/*--------------------------------------*/
int main(int ac, char *av[])
{
	int i, j, k, dd;

	if(ac != 3)
	{
		printf("usage: %s  91  5 ・・・ 1991年5月のカレンダ出力\n", av[0]);
		return 0;
	}
	date.tm_year = atoi(av[1]); /* 19xx年 */
	date.tm_mon = atoi(av[2]) - 1; /* x月 */
	date.tm_mday = 1; /* 1日 */
	_mjd(&date);
	dd = _mday[date.tm_mon];

	j = date.tm_wday;
	for(i = 0; i < j; i++)	printf("   ");

	for(i = 1; i <= dd; i++)
	{
		date.tm_mday = i;
		k = _holiday(&date);
		if(k != 0)		printf("\x1b[31m");
		else if(j == 0)	printf("\x1b[31m");
		else if(j == 6)	printf("\x1b[34m");
		printf("%3d\x1b[0m", i);
		j = (j + 1) % 7;
		if(j == 0)	putchar('\n');
	}
	putchar('\n');

	return 1;
}

出力例           top (トップに戻る)
           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