/*
* cal.c *
* Created on: Apr 10, 2011 * Author: Administrator *
* 现行的格里历是从儒略历演化而来的。儒略历每4年一个润年,润年366天,平年365天。
* 如果从公元1年算的话,那么凡是能够被4整除的都是润年。从天文角度看,儒略历这种
* 历法是有误差的,到16世纪误差已经达到了10天。1582年,罗马教皇对儒略历进行了
* 一次校定,该年的10-5到10-14这10天被抹掉,并规定凡不能被400整除的世纪年不再
* 算为润年,校定之后的儒略历即为现行的格里历。 *
* 但是英国直到1752年才开始使用格里历,此时时间误差已经达到了11天,原因是1700
* 年在儒略历中是润年,而在格里历中是平年。1752年英国议会决定将本年的9-3到9-13
* 这11天抹掉,以同步格里历。当时美国不是英国的殖民地,所以在美国的日历中也是没有
* 1752-9-3到1752-9-13这11天的。 我们知道UNIX系统源于美国,Linux系统源于UNIX,
* 这就是为什么当我们在Linux系统中敲\这条命令时,会看到一个只有19天
* 的9月。 *
* 以上内容参考自维基百科 *
* 本程序模似Linux中cal命令的部分功能。允许输入的年分为1...9999。 * 编译器:gcc V4.5.0 *
* 分析:
* 1752年是特殊年,1752-9月是特殊年中的特殊月。 *
* 1752-9-2之前,采用的是儒略历,凡能被4整除都为润年;1752-9-14之后,采用的是
* 格里历,不能被400整除的世纪年不再作为润年。 *
* 格里历闰年计算方法 * 世纪年 ***4000的倍数 **3200/1900的倍数 400的倍数 100的倍数 4的倍数
* 结果 不闰 不闰 闰 不闰 闰 * 注:
* 3200/1900的倍数是天文科学家研究出来
* 增加4000的倍数不闰更准确,但目前只是世纪年还不足4000,因此尚未用途 *
* 格里历在400年的周期中有146,097天,恰好是20,871 星期。所以,例如,格里历七年、
* 407年、807年、1207年、1607年、2007年的日期与星期是完全相同的。也就是说,格里
* 历每400年一个周期。 *
* 公元1-1-1,按儒略历是周六,按格里历是周一;因1752-9-2之前采用的都是儒略历,所以
* 公元1-1-1应该是周六。 * 1752-9-14是周四。 *
* 公元1-1-1到1752-9-2,日期是连续的,儒略历;公元1752-9-14至今,日期是连续的,格里历。 *
* 对于给定的一个 年(Y)-月(M)-日(D) ,则从公元1-1-1到 给定的日期的天数为:
* 1752-9-2前:365*(Y-1)+(Y-1)/4+e,其中e表示从Y-1-1到Y-M-D的天数,
* 且这天是该周的第((Y-1)+(Y-1)/4+5+e)%7天。 *
* 1752-9-14后:365*(Y-1)+(Y-1)/4-(Y-1)/100+(Y-1)/400+e, * 且这天是该周的第((Y-1)+(Y-1)/4-(Y-1)/100+(Y-1)/400+e)%7天。
*
* 需要注意的是,从1-1-1到1752-9-14之后的某个日期的天数并非实际的天数,它只是根据格里历的
* 的规则推算出来的,目的也只是为了得到日期与星期的对应。 *
* 算法思想:
* 对于年历,若能知道本年的1月1日是周几,也就知道了本年的年历分布。 * 对于月历,若能知道本月的1日是周几,也就知道了本月的月历分布。 * 所以关键是正确的推算出给定的一个日期是星期几。以下为推算方法: * 1752-9-2之前:((Y-1)+(Y-1)/4+5+e)%7
* 1752-9-14之后:((Y-1)+(Y-1)/4-(Y-1)/100+(Y-1)/400+e)%7 * 把1800-2199年当成一个周期,对于其后的日期,只需在1800-2199之间找到
* 对应的日期,就可以知道是星期几,这样就不用再考虑4000年之后4000的倍数
* 不是润年这种情况。 (Y-1800)@0+1800 * *
* */
#include
int CheckYear(int year); int CheckMonth(int month);
int CheckDay(int year, int month, int day); int IsNum(char *argv);
int IsLegalParameter(int argc, char **argv); long StrToLong(char *argv);
long Power(int baseNumber, int exponent); void PrintCalendar(int year);
void PrintCommonCalendar(int year, int row); void PrintOneQuarter(int year, int mfOfWeek, int mfDays, int msOfWeek, int msDays, int mtOfWeek, int mtDays, int row); void Print1752_3Quarter();
void PrintMonthlyCalendar(int year, int month); void PrintMonthName(char *, int year);
void PrintCommonMonthlyCalendar(int dayOfWeek, int days); void PrintDayOfWeek(int year, int month, int day); int DayOfWeek(int year, int month, int day); int CurrentDays(int year, int month, int day);
int a;//输入的年这个参数的字符串长度,主根用于后面的PrintMonthName(char *, int)函数
int main(int argc, char **argv) { int year, month, day;
int flag = IsLegalParameter(argc, argv); switch (flag) { case -1:
printf(\); PrintHelp(); break; case 0:
PrintMonthlyCalendar(*(CurrentCal()), *(CurrentCal() + 1)); break; case 1: {
a = strlen(*(argv + 1)); switch (argc) { case 2:
year = StrToLong(*(argv + 1)); if (!CheckYear(year)) { break; }
printf(\, year); PrintCalendar(year); break; case 3:
year = StrToLong(*(argv + 1)); if (!CheckYear(year)) { break;
}
month = StrToLong(*(argv + 2)); month = StrToLong(*(argv + 2)); if (!CheckMonth(month)) { break; }
PrintMonthlyCalendar(year, month); break; case 4:
year = StrToLong(*(argv + 1)); if (!CheckYear(year)) { break; }
month = StrToLong(*(argv + 2)); if (!CheckMonth(month)) { break; }
day = StrToLong(*(argv + 3));
if (!CheckDay(year, month, day)) { break; }
PrintDayOfWeek(year, month, day); break; default:
year = StrToLong(*(argv + 1)); if (!CheckYear(year)) { break; }
month = StrToLong(*(argv + 2)); if (!CheckMonth(month)) { break; }
day = StrToLong(*(argv + 3));
if (!CheckDay(year, month, day)) { break; }
PrintDayOfWeek(year, month, day); break; } }
default: break; }
return 0; }
void PrintHelp() {
printf(\:cal [
int CheckYear(int year) {
if (year == 0 || year > 9999) {
printf(\, year); return 0; }
return 1; }
int CheckMonth(int month) {
if (month < 1 || month > 12) {
printf(\, month); return 0; }
return 1; }
int CheckDay(int year, int month, int day) { switch (month) { case 1:
if (day < 1 || day > 31) {
printf(\, day); return 0; }
return 1; break; case 2:
if ((year < 1753 && year % 4 == 0) || ((year % 4 == 0 && year % 100
!= 0) || year % 400 == 0)) { if (day < 1 || day > 29) {
printf(\, day); return 0; } }
if (day < 1 || day > 28) {
printf(\, day); return 0; }
return 1; break; case 3:
if (day < 1 || day > 31) {
printf(\, day); return 0; }
return 1; break; case 4:
if (day < 1 || day > 30) {
printf(\, day); return 0; }
return 1; break; case 5: