您的位置:首页 > 运维架构 > Linux

linux下c/c++实例之一万年历

2015-11-04 17:58 507 查看


一、简介

      Linux系统自带万年历程序,可以使用cal 11 2015命令查看11月份的日历。




二、详解

1、代码一

(1)calendar.c:#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
if (argc != 2) {
printf("usage: [%s 2000/10/1] or [%s 2000/10]\n", argv[0], argv[0]);
return -1;
}
int year = 0, month = 0, day = 0, week = 0, days = 0;
int i = 0;
int flag = -1; //分隔年月日
int dm = 0; //月不同,与标准天的星期1-7天数的偏差
int dy = 0; //年不同,引起的星期1-7天数的偏差
int m2 = 0; //2月,引起的星期1-7天数的偏差
char WEEK[9] = {0};

while(argv[1][i]) { /*遍历传入的参数日期,计算出year,month,day*/
if ((argv[1][i] == '/' || argv[1][i] == '.' || argv[1][i] == '-') && flag == -1 ) {
flag = 0;
i++;
continue;
}
if ((argv[1][i] == '/' || argv[1][i] == '.' || argv[1][i] == '-') && flag == 0 ) {
flag = 1;
i++;
continue;
}
if (flag == -1) year = year * 10 + (argv[1][i] - '0');
if (flag == 0) month = month * 10 + (argv[1][i] - '0');
if (flag == 1) day = day * 10 + (argv[1][i] - '0');
i++;
}
if (month < 1 || month > 12 || year < 0) { /*若月份传入错误数字*/
printf ("ERROR! the entered MONTH or YEAR is invalid\n");
return -1;
}
if (year == 2000) {
dy = 0; //以2000/1/1为基准点
m2 = 1; //29天
}
else {
/*** 该年 1月1号 到2000年1月1号的 " 天数差 " ***/
if(year > 2000) dy =(year -2000 ) + (year-1-2000)/4 - (year-1-2000)/100 + (year-1-2000)/400 + 1;
else dy =(year -2000 ) + (year-2000)/4 - (year-2000)/100 + (year-2000)/400;
if((year%4 == 0 && year%100 != 0) || (year%100 == 0 && year%400 == 0)) m2 = 1;
else m2 = 0; /***该年不是润年***/
}
switch (month) {
case 1: dm = 0; days = 31; break; //31%7 == 3得偏移天数
case 2: dm = 3; days = (m2 == 1 ? 29 : 28); break;
case 3: dm = 3 + m2; days = 31; break;
case 4: dm = 6 + m2; days = 30; break;
case 5: dm = 1 + m2; days = 31; break;
case 6: dm = 4 + m2; days = 30; break;
case 7: dm = 6 + m2; days = 31; break;
case 8: dm = 2 + m2; days = 31; break;
case 9: dm = 5 + m2; days = 30; break;
case 10: dm = m2; days = 31; break;
case 11: dm = 3 + m2; days= 30; break;
case 12: dm = 5 + m2; days = 31; break;
}
if (day < 0 || day > days) {
printf ("ERROR! the entered DAY is invalid\n");
exit (0);
}
week = (dy + dm + day - 1 + 6) % 7;
if (week < 0) week += 7;
if (day > 0) { /*** 判定查看类型 ***/
switch (week) {
case 0: strcpy (WEEK,"SUNDAY"); break;
case 1: strcpy (WEEK,"MONDAY"); break;
case 2: strcpy (WEEK,"TUESDAY"); break;
case 3: strcpy (WEEK,"WEDNESDAY"); break;
case 4: strcpy (WEEK,"THURSDAY"); break;
case 5: strcpy (WEEK,"FRIDAY"); break;
case 6: strcpy (WEEK,"SATURDAY"); break;
}
printf ("this day is %s[%d]\nOK!\n", WEEK, week);
}
else {
week = (++week ) % 7;
printf ("the calender of this month as following\n");
printf ("\n*********************************\n");
printf (" SUN MON TUE WEN THU FRI STA\n");
for (i = 0; i < week; i++) printf (" ");
for (i = 1; i <= days; i++) {
printf (" %2d ",i);
week++;
if (week % 7 == 0 && i != days) printf ("\n");
}
printf ("\n*********************************\n");
printf ("OK!\n");
}
return 0;
}(2)编译运行
gcc -o calendar calendar.c
./calendar 2015/11



./calendar 2015/11/4



2、代码二

(1)calendar.c:
/*
* 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系统中敲"cal 9 1752"这条命令时,会看到一个只有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)%400+1800
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static void PrintHelp();
static int* CurrentCal();
static int CheckYear(int year);
static int CheckMonth(int month);
static int CheckDay(int year, int month, int day);
static int IsNum(char *argv);
static int IsLegalParameter(int argc, char **argv);
static long StrToLong(char *argv);
static long Power(int baseNumber, int exponent);
static void PrintCalendar(int year);
static void PrintCommonCalendar(int year, int row);
static void PrintOneQuarter(int year, int mfOfWeek, int mfDays, int msOfWeek, int msDays, int mtOfWeek, int mtDays, int row);
static void Print1752_3Quarter();
static void PrintMonthlyCalendar(int year, int month);
static void PrintMonthName(char *, int year);
static void PrintCommonMonthlyCalendar(int dayOfWeek, int days);
static void PrintDayOfWeek(int year, int month, int day);
static int DayOfWeek(int year, int month, int day);
int CurrentDays(int year, int month, int day);

int len_year = 0;	//输入的年这个参数的字符串长度,主根用于后面的PrintMonthName(char *, int)函数
int cal[3] = {0};

int main(int argc, char **argv)
{
int year = 0, month = 0, day = 0;
int flag = IsLegalParameter(argc, argv);
switch(flag) {
case -1:
printf("Syntax Error!\n\n");
PrintHelp();
break;
case 0:
PrintMonthlyCalendar(*(CurrentCal()), *(CurrentCal() + 1));
break;
case 1: {
len_year = strlen(*(argv + 1));
switch(argc) {
case 2:
year = StrToLong(*(argv + 1));
if (!CheckYear(year))  break;
printf("                               %4d\n\n", year);
PrintCalendar(year);
break;
case 3:
year = StrToLong(*(argv + 1));
if (!CheckYear(year))  break;
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;
}
break;
}
default:  break;
}
return 0;
}
void PrintHelp()
{
printf("usage:cal [<YEAR> [<MONTH> [<DAY>]]");
}
/*
*以下函数判断输入的参数是否合法
*/
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表示输入了参数,并且参数是合法的
}
/*
* 以下函数判断一个字符串是否能被转换成数字
*/
int IsNum(char *argv) {
while (*argv != '\0') {
if (*argv >= 48 && *argv <= 57) {
argv++;
continue;
}
return 0;
}
return 1;
}
/**
* 以下函数返回一个包含当前年 月 日的整型数组
*/
int* CurrentCal()
{
time_t nowtime;
struct tm *timeinfo;
time(&nowtime);
timeinfo = localtime(&nowtime);
memset(cal, 0, sizeof(cal));
cal[0] = timeinfo->tm_year + 1900;
cal[1] = timeinfo->tm_mon + 1;
cal[2] = timeinfo->tm_mday;
//printf("data=%d, %d, %d\n", cal[0], cal[1], cal[2]);
return cal;
}
/**
* 打印指定月的月历
*/
void PrintMonthlyCalendar(int year, int month)
{
int dayOfWeek = DayOfWeek(year, month, 1);
switch (month) {
case 1:
PrintMonthName("January", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 2:
PrintMonthName("February", 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("March", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 4:
PrintMonthName("April", year);
PrintCommonMonthlyCalendar(dayOfWeek, 30);
break;
case 5:
PrintMonthName("May", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 6:
PrintMonthName("June", year);
PrintCommonMonthlyCalendar(dayOfWeek, 30);
break;
case 7:
PrintMonthName("July", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 8:
PrintMonthName("August", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 9:
PrintMonthName("September", year);
if (year == 1752) {   //特殊的1752-9
printf("Su Mo Tu We Th Fr Sa\n       1  2 14 15 16\n17 18 19 20 21 22 23\n24 25 26 27 28 29 30\n");
break;
}
PrintCommonMonthlyCalendar(dayOfWeek, 30);
break;
case 10:
PrintMonthName("October", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
case 11:
PrintMonthName("November", year);
PrintCommonMonthlyCalendar(dayOfWeek, 30);
break;
case 12:
PrintMonthName("December", year);
PrintCommonMonthlyCalendar(dayOfWeek, 31);
break;
default:
break;
}
}
/**
* 以下函数返回给定的年、月、日是周几
*/
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;
}
/**
* 以下函数的作用仅仅是将月名在水平方向上打印到月历的中间
*/
void PrintMonthName(char *monthName, int year)
{
char space = 32;
int preSpaces = 0;
preSpaces = (21 - strlen(monthName) - len_year - 1) / 2;
printf("%*c%s %d\n", preSpaces, space, monthName, year);
printf("--------------------\n");
}
/**
* 根据一个月的天数及该月有几天这两个参数,打印出该月的月历
*/
void PrintCommonMonthlyCalendar(int dayOfWeek, int days)
{
int i, j, day = 1;
char space = 32;
int weeks = (days + dayOfWeek) / 7 + 1; //计算出该月有几周
printf("Su Mo Tu We Th Fr Sa\n");
printf("%*c", 3 * dayOfWeek, space);
for (i = 0; i < weeks; ++i) {
if (i == 0) {
//打印第1周
for (j = dayOfWeek; j < 7; ++j) {
printf("%2d ", day);
day++;
}
continue;
}
//打印第2周到倒数第2周
if (i < weeks - 1) {
printf("\n%2d %2d %2d %2d %2d %2d %2d", day, day + 1, day + 2, day + 3, day + 4, day + 5, day + 6);
day += 7;
continue;
}
//打印最后一周
printf("\n");
for (j = 0; j < 7; ++j) {
if (day <= days) {
printf("%2d ", day++);
}
}
printf("\n");
}
}
/**
* 以下函数将一个字符串转换成数字。
*/
long StrToLong(char *argv)
{
if (!IsNum(argv)) {
return 0;
}
long result = 0;
int argvLength = strlen(argv);
int *nums = (int *)malloc((argvLength + 1) * sizeof(int));
memset(nums, 0, (argvLength + 1) * sizeof(int));
//int nums[1000] = {0};
int *pInt = nums;
int i = 0;
do {
*(pInt++) = *argv - 48;
int num = *argv - 48;
argv++;
} while(*argv != '\0');
pInt = nums;
do {
result += *pInt * Power(10, argvLength - 1);
pInt++;
argvLength--;
} while (argvLength != 0);
free(nums);
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;
}
int CheckYear(int year)
{
if (year == 0 || year > 9999) {
printf("cal: year %d not in range 1..9999\n", year);
return 0;
}
return 1;
}
int CheckMonth(int month)
{
if (month < 1 || month > 12) {
printf("cal: month %d not in range (1..12)\n", month);
return 0;
}
return 1;
}
int CheckDay(int year, int month, int day)
{
switch (month) {
case 1:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", 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("cal: day %d not in range (1..29)\n", day);
return 0;
}
}
if (day < 1 || day > 28) {
printf("cal: day %d not in range (1..28)\n", day);
return 0;
}
return 1;
break;
case 3:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
case 4:
if (day < 1 || day > 30) {
printf("cal: day %d not in range (1..30)\n", day);
return 0;
}
return 1;
break;
case 5:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
case 6:
if (day < 1 || day > 30) {
printf("cal: day %d not in range (1..30)\n", day);
return 0;
}
return 1;
break;
case 7:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
case 8:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
case 9:
if (day < 1 || day > 30) {
printf("cal: day %d not in range (1..30)\n", day);
return 0;
}
return 1;
break;
case 10:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
case 11:
if (day < 1 || day > 30) {
printf("cal: day %d not in range (1..30)\n", day);
return 0;
}
return 1;
break;
case 12:
if (day < 1 || day > 31) {
printf("cal: day %d not in range (1..31)\n", day);
return 0;
}
return 1;
break;
default:
break;
return 0;
}
}
/**
* 打印给定的年、月、日是周几
*/
void PrintDayOfWeek(int year, int month, int day)
{
char *names[9] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
int dayOfWeek = DayOfWeek(year, month, day);
if (dayOfWeek == -1)  return;
printf("%d-%d-%d: %s\n", year, month, day, *(names + dayOfWeek));
}
/**
* 以下函数打印年历,以月为单位,分成四行打印,每行打印三个月
*/
void PrintCalendar(int year)
{
int i;
for (i = 0; i < 4; ++i) {
switch (i) {
case 0:
//打印第1行,1-3月的月历
printf("       January              February               March\n");
printf("--------------------  --------------------  --------------------\n");
printf("Su 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("        April                  May                  June\n");
printf("--------------------  --------------------  --------------------\n");
printf("Su 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("        July                 August              September\n");
printf("--------------------  --------------------  --------------------\n");
printf("Su 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("       October              November              December\n");
printf("--------------------  --------------------  --------------------\n");
printf("Su 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("%*c", 3 * mfOfWeek, space);
}
for (j = mfOfWeek; j < 7; ++j) {
printf("%2d ", mfDay);
mfDay++;
}
//输出第二个月的第一周
printf("%*c", 3 * msOfWeek + 1, space);
for (j = msOfWeek; j < 7; ++j) {
printf("%2d ", msDay);
msDay++;
}
//输出第三个月的第一周
printf("%*c", 3 * mtOfWeek + 1, space);
for (j = mtOfWeek; j < 7; ++j) {
printf("%2d ", mtDay);
mtDay++;
}
continue;
}

//打印2-4周
if (i < 4) {
printf("\n%2d %2d %2d %2d %2d %2d %2d  %2d %2d %2d %2d %2d %2d %2d  %2d %2d %2d %2d %2d %2d %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("\n%2d %2d %2d %2d %2d %2d %2d ", mfDay, mfDay + 1, mfDay + 2, mfDay + 3, mfDay + 4, mfDay + 5, mfDay + 6);
mfDay += 7;
}
else {   //未打印天数不足一周时,按以下方式打印
printf("\n");
for (j = 0; j < 7; ++j) {
//有数据打印数据,没有数据用空格填充
if (mfDay <= mfDays) {
printf("%2d ", mfDay++);
}
else {
printf("   ");
}
}
}
printf(" ");

//打印第2个月的第5周或第6周
if (msDays - msDay > 6) {
printf("%2d %2d %2d %2d %2d %2d %2d ", 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("%2d ", msDay++);
}
else {
printf("   ");
}
}
}
printf(" ");

//打印第3个月的第5周或第6周
if (mtDays - mtDay > 6) {
printf("%2d %2d %2d %2d %2d %2d %2d ", 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("%2d ", mtDay++);
}
}
}
}
printf("\n");
}
/**
*特殊的1752年第3季度:7月8月9月
*/
void Print1752_3Quarter()
{
char space = 32;
printf("%10c1  2  3  4%21c1%9c1  2 14 15 16\n", 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("12 13 14 15 16 17 18   9 10 11 12 13 14 15  24 25 26 27 28 29 30\n");
printf("19 20 21 22 23 24 25  16 17 18 19 20 21 22\n");
printf("26 27 28 29 30 31     23 24 25 26 27 28 29\n");
printf("%22c30 31\n", space);
}
(2)编译运行:
gcc -o calendar calendar.c
./calendar(等同于./calendar 2015 11)



./calendar 2015



./calendar 2015 11 4




三、总结

(1)万年历的算法还是比较复杂的,需要考虑的因素比较多,也可看看linux系统的源码包util-linux-ng参考万年历的实现。

(2)若有建议,请留言,在此先感谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c linux