万年历算法的实现
更新时间:2024-05-26 20:06:01 阅读量: 综合文库 文档下载
/*
* 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:
if (day < 1 || day > 31) {
printf(\, day); return 0; }
return 1; break; case 6:
if (day < 1 || day > 30) {
printf(\, day); return 0; }
return 1; break; case 7:
if (day < 1 || day > 31) {
printf(\ return 0; }
return 1; break; case 8:
if (day < 1 || day > 31) {
printf(\ return 0; }
return 1; break; case 9:
if (day < 1 || day > 30) {
printf(\ return 0; }
return 1; break; case 10:
if (day < 1 || day > 31) {
printf(\ return 0; }
return 1; break; case 11:
if (day < 1 || day > 30) {
printf(\ return 0; }
return 1; break; case 12:
if (day < 1 || day > 31) {
printf(\ return 0;
, day); , day); , day); , day); , day); , day); }
return 1; break; default: break; return 0; } } /**
* 以下函数返回一个包含当前年 月 日的整型数组 */
int* CurrentCal() { time_t nowtime;
struct tm *timeinfo; time(&nowtime);
timeinfo = localtime(&nowtime); int cal[3];
cal[0] = timeinfo->tm_year + 1900; cal[1] = timeinfo->tm_mon + 1; cal[2] = timeinfo->tm_mday; return cal; } /**
* 以下函数打印年历,以月为单位,分成四行打印,每行打印三个月 */
void PrintCalendar(int year) { int i;
for (i = 0; i < 4; ++i) { switch (i) { case 0:
//打印第1行,1-3月的月历
printf(\March\\n\);
printf(
\--------------------\\n\); printf(
\Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa\\n\);
PrintCommonCalendar(year, 1); break; case 1:
//打印第2行,4-6月的月历
printf(\June\\n\);
printf(
\--------------------\\n\); printf(
\Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa\\n\);
PrintCommonCalendar(year, 2); break; case 2:
//打印第3行,7-9月的月历 printf(
\September\\n\); printf(
\--------------------\\n\); printf(
\Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa\\n\);
PrintCommonCalendar(year, 3); break; case 3:
//打印第4行,11-12月的月历 printf(
\December\\n\);
printf(
\--------------------\\n\); printf(
\Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa\\n\);
PrintCommonCalendar(year, 4); break; default: break; } } } /**
* 打印出给定年,给定行的3个月的月历。 */
void PrintCommonCalendar(int year, int row) {
int mfOfWeek, mfDays; //mfOfWeek表示该行第1个月的1号是周几,mfDays表示第1个月的天数
int msOfWeek, msDays; //mfOfWeek表示该行第2个月的1号是周几,mfDays表示第2个月的天数
int mtOfWeek, mtDays; //mfOfWeek表示该行第3个月的1号是周几,mfDays表示第3个月的天数 switch (row) { case 1:
mfOfWeek = DayOfWeek(year, 1, 1); mfDays = 31;
msOfWeek = DayOfWeek(year, 2, 1); msDays = 28;
mtOfWeek = DayOfWeek(year, 3, 1); mtDays = 31;
PrintOneQuarter(year, mfOfWeek, mfDays, msOfWeek, msDays, mtOfWeek,
mtDays, row); break; case 2:
mfOfWeek = DayOfWeek(year, 4, 1); mfDays = 30;
msOfWeek = DayOfWeek(year, 5, 1); msDays = 31;
mtOfWeek = DayOfWeek(year, 6, 1); mtDays = 30;
PrintOneQuarter(year, mfOfWeek, mfDays, msOfWeek, msDays, mtOfWeek,
mtDays, row); break; case 3:
if (year == 1752) {
Print1752_3Quarter(); break; }
mfOfWeek = DayOfWeek(year, 7, 1); mfDays = 31;
msOfWeek = DayOfWeek(year, 8, 1); msDays = 31;
mtOfWeek = DayOfWeek(year, 9, 1); mtDays = 30;
PrintOneQuarter(year, mfOfWeek, mfDays, msOfWeek, msDays, mtOfWeek,
mtDays, row); break; case 4:
mfOfWeek = DayOfWeek(year, 10, 1); mfDays = 31;
msOfWeek = DayOfWeek(year, 11, 1); msDays = 30;
mtOfWeek = DayOfWeek(year, 12, 1); mtDays = 31;
PrintOneQuarter(year, mfOfWeek, mfDays, msOfWeek, msDays, mtOfWeek,
mtDays, row); break; default: break; } } /**
* 以下函数打印一个季度,也即是在同一行上的3个月的月历。 *
* 打印方式肯定是从上到下,从左到右依次打印。 *
* 每月至多有6周,至少有5周;第1周、第5周和第6周(如果有第6周)是需要特殊处理 * 的三个周,因为这3周并不一定总是有7天。 */ void PrintOneQuarter(int year, int mfOfWeek, int mfDays, int msOfWeek, int msDays, int mtOfWeek, int mtDays, int row) {
int mfDay = 1, msDay = 1, mtDay = 1; //对已经打印的天数记数 int i, j;
char space = 32;
//如果要打印的是1-3月的月历,则应该判断一下该年的2月是29天不是29天 if (row == 1) {
if ((year < 1753 && year % 4 == 0) || (year >= 1753 && ((year % 4 == 0
&& year % 100 != 0) || year % 400 == 0))) { msDays = 29; } }
for (i = 0; i < 6; ++i) { if (i == 0) {
//输出第一个月的第一周 if (mfOfWeek > 0) {
printf(\, 3 * mfOfWeek, space); }
for (j = mfOfWeek; j < 7; ++j) { printf(\, mfDay); mfDay++; }
//输出第二个月的第一周
printf(\, 3 * msOfWeek + 1, space); for (j = msOfWeek; j < 7; ++j) { printf(\, msDay); msDay++; }
//输出第三个月的第一周
printf(\, 3 * mtOfWeek + 1, space); for (j = mtOfWeek; j < 7; ++j) { printf(\, mtDay); mtDay++; }
continue; }
//打印2-4周 if (i < 4) { printf(
\
2d - - - - - -\,
mfDay, mfDay + 1, mfDay + 2, mfDay + 3, mfDay + 4, mfDay
+ 5, mfDay + 6, msDay, msDay + 1, msDay + 2, msDay
+ 3, msDay + 4, msDay + 5, msDay + 6, mtDay, mtDay
+ 1, mtDay + 2, mtDay + 3, mtDay + 4, mtDay + 5,
mtDay + 6); mfDay += 7; msDay += 7; mtDay += 7; continue; }
//打印第1个月的第5周或第6周
if (mfDays - mfDay > 6) { //未打印天数不少于7天时,能够占满1周,直接打印
printf(\- - - - - - \, mfDay, mfDay + 1, mfDay
+ 2, mfDay + 3, mfDay + 4, mfDay + 5, mfDay + 6); mfDay += 7;
} else { //未打印天数不足一周时,按以下方式打印 printf(\);
for (j = 0; j < 7; ++j) {
//有数据打印数据,没有数据用空格填充 if (mfDay <= mfDays) {
printf(\, mfDay++); } else {
printf(\); } } }
printf(\);
//打印第2个月的第5周或第6周 if (msDays - msDay > 6) {
printf(\, msDay, msDay + 1, msDay + 2,
msDay + 3, msDay + 4, msDay + 5, msDay + 6); msDay += 7; } else {
for (j = 0; j < 7; ++j) { if (msDay <= msDays) {
printf(\, msDay++); } else {
printf(\); } } }
printf(\);
//打印第3个月的第5周或第6周 if (mtDays - mtDay > 6) {
printf(\, mtDay, mtDay + 1, mtDay + 2,
mtDay + 3, mtDay + 4, mtDay + 5, mtDay + 6); mtDay += 7; } else {
for (j = 0; j < 7; ++j) { if (mtDay <= mtDays) {
printf(\, mtDay++); } } } }
printf(\); } /**
*特殊的1752年第3季度:7月8月9月 */
void Print1752_3Quarter() { char space = 32;
printf(\, space, space, space);
printf(\5 6 7 8 9 10 11 2 3 4 5 6 7 8 17 18 19 20 21 22 23\\n\);
printf(\29 30\\n\);
printf(\); printf(\); printf(\, space); } /**
* 打印指定月的月历 */
void PrintMonthlyCalendar(int year, int month) { int dayOfWeek = DayOfWeek(year, month, 1); switch (month) { case 1:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 2:
PrintMonthName(\, year); if (year < 1753 && year % 4 == 0) {
PrintCommonMonthlyCalendar(dayOfWeek, 29); break;
} else if ((year % 4 == 0 && year % 100 != 0) || year % 400 ==
0) {
PrintCommonMonthlyCalendar(dayOfWeek, 29); break; }
PrintCommonMonthlyCalendar(dayOfWeek, 28); break; case 3:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 4:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 30); break; case 5:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 6:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 30); break; case 7:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 8:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 9:
PrintMonthName(\, year); if (year == 1752) { //特殊的1752-9 printf(
\20 21 22 23\\n24 25 26 27 28 29 30\); break; }
PrintCommonMonthlyCalendar(dayOfWeek, 30); break; case 10:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; case 11:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 30); break; case 12:
PrintMonthName(\, year);
PrintCommonMonthlyCalendar(dayOfWeek, 31); break; default: break; } } /**
* 以下函数的作用仅仅是将月名在水平方向上打印到月历的中间 */
void PrintMonthName(char *monthName, int year) { char space = 32; int preSpaces = 0;
preSpaces = (21 - strlen(monthName) - a - 1) / 2;
printf(\, preSpaces, space, monthName, year); printf(\); } /**
* 根据一个月的天数及该月有几天这两个参数,打印出该月的月历 */
void PrintCommonMonthlyCalendar(int dayOfWeek, int days) { int i, j, day = 1; char space = 32;
int weeks = (days + dayOfWeek) / 7 + 1; //计算出该月有几周 printf(\); printf(\, 3 * dayOfWeek, space); for (i = 0; i < weeks; ++i) { if (i == 0) { //打印第1周
for (j = dayOfWeek; j < 7; ++j) { printf(\, day); day++; }
continue; }
//打印第2周到倒数第2周 if (i < weeks - 1) {
printf(\, day, day + 1, day + 2, day
+ 3, day + 4, day + 5, day + 6); day += 7; continue; }
//打印最后一周 printf(\);
for (j = 0; j < 7; ++j) { if (day <= days) {
printf(\, day++); } }
printf(\); } } /**
* 打印给定的年、月、日是周几 */
void PrintDayOfWeek(int year, int month, int day) {
char *names[9] = { \, \, \, \, \,
\, \ };
int dayOfWeek = DayOfWeek(year, month, day); if (dayOfWeek == -1) { return; }
printf(\%s\\n\, year, month, day, *(names + dayOfWeek)); } /**
* 以下函数返回给定的年、月、日是周几 */
int DayOfWeek(int year, int month, int day) {
if ((year < 1752) || (year == 1752 && month < 9) || (year == 1752 && month
== 9 && day < 3)) {
return ((year - 1) + (year - 1) / 4 + CurrentDays(year, month, day) + 5)
% 7; }
if (year == 1752 && month == 9 && (day > 2 && day < 14)) { printf(\本万年历中没有%d-%d-%d这一天\\n\, year, month, day); return -1; }
if (year > 2199) {
year = (year - 1800) % 400 + 1800; }
return ((year - 1) + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400
+ CurrentDays(year, month, day)) % 7; } /**
* 以下函数计算从给定年的1-1到month-day的天数 */
int CurrentDays(int year, int month, int day) {
int days = 0; switch (month) { case 1:
days = day; break; case 2:
days = 31 + day; break; case 3:
days = 59 + day; break; case 4:
days = 90 + day; break; case 5:
days = 120 + day; break; case 6:
days = 151 + day; break; case 7:
days = 181 + day; break; case 8:
days = 212 + day; break; case 9:
days = 243 + day; break; case 10:
days = 273 + day; break; case 11:
days = 304 + day; break; case 12:
days = 334 + day; break; default: break; }
if (year < 1753 && year % 4 == 0) { if (month > 2) { ++days; }
} else if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { if (month > 2) { ++days; }
}
return days; } /*
* 以下函数判断一个字符串是否能被转换成数字 */
int IsNum(char *argv) { while (*argv != '\\0') {
if (*argv >= 48 && *argv <= 57) { argv++; continue; }
return 0; }
return 1; } /*
*以下函数判断输入的参数是否合法 */
int IsLegalParameter(int argc, char **argv) { if (argc == 1) {
return 0; //0表示没有输入参数 }
while (argc > 1) {
if (!IsNum(*(argv + --argc))) {
return -1; //-1表示输入的参数不合法 } }
return 1; //1表示输入了参数,并且参数是合法的 } /**
* 以下函数将一个字符串转换成数字。 */
long StrToLong(char *argv) { if (!IsNum(argv)) { return 0; }
long result = 0;
int argvLength = strlen(argv); int nums[argvLength - 1]; int *pInt = nums;
do {
*(pInt++) = *argv - 48; argv++;
} while (*argv != '\\0');
pInt = nums;
do {
result += *pInt * Power(10, argvLength - 1); pInt++;
argvLength--;
} while (argvLength != 0); return result; } /*
* According to the base number and the exponent calculate power. * 根据基数和指数,计算出乘方数。 */
long Power(int baseNumber, int exponent) { long result = 1;
if (exponent == 0) { return 1; } do {
result *= baseNumber; exponent--;
} while (exponent != 0); return result; }
正在阅读:
万年历算法的实现05-26
模具毕业设计37后油箱注射成型模具的设计04-10
博艺幼儿园教师工资考核分配方案03-13
当前希望解决的思想理论问题09-18
初中语文1-6册总复习04-17
北京市朝阳区中学明德分校2020-2021学年九年级上学期期末模拟试题二(人教版)05-16
建筑节能设计在实践中应用06-12
2018-2024年中国互联网+低速电动车行业市场竞争趋势报告(目录)05-23
群众路线教育实践活动学习笔记12-11
2013年信息技术基础模拟题及答案05-22
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 万年历
- 算法
- 实现
- 初中“六一儿童节”庆祝活动方案word精品模板
- 2015选调生申论范文:推进结构调整 构建消费大国1
- 农业技术推广法
- 许昌学院马克思基本原理网络题库单选题(含答案)
- 数据库课程设计(企业员工工资管理系统) (1)
- 江苏省污水处理企业名录2018版752家 - 图文
- 关于民族舞蹈文化传承与发扬之我见
- peppa pig一季1到51集重要单词解析
- 蚂蚁团队模式解读(制定人:沈岗)
- 最新购机流程
- 如何给孩子起名呢
- 2015-2020年中国太阳能热水器行业市场分析与发展前景评估报告 -
- 塑料成型工艺与模具设计习题与答案 - 图文
- 2011年司考真题卷三
- 中 科 软:定向增资结果报告书
- 饥荒攻略 - 图文
- 《分析化学》习题选编 - 图文
- 汉字听写大赛(生僻字)
- 实验室管理体系质量手册 - 图文
- 网络工程师在线学习与考试信息系统需求分析报告