当前位置:文档之家› 万年历算法的实现

万年历算法的实现

万年历算法的实现
万年历算法的实现

/*

* 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

#include

#include

void PrintHelp();

int* CurrentCal();

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("Syntax Error!\n\n");

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(" %4d\n\n", 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("usage:cal [ [ []]"); }

int CheckYear(int year) {

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:

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;

}

}

/**

* 以下函数返回一个包含当前年月日的整型数组

*/

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(" 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);

}

/**

* 打印指定月的月历

*/

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");

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;

}

}

/**

* 以下函数的作用仅仅是将月名在水平方向上打印到月历的中间

*/

void PrintMonthName(char *monthName, int year) {

char space = 32;

int preSpaces = 0;

preSpaces = (21 - strlen(monthName) - a - 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");

}

}

/**

* 打印给定的年、月、日是周几

*/

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)); }

/**

* 以下函数返回给定的年、月、日是周几

*/

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) {

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;

}

}

}

/*

* 以下函数判断一个字符串是否能被转换成数字

*/

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;

}

数字万年历的制作

数字万年历的制作 数字显示万年历,它采用一枚专用软封装的时钟芯片,驱动15只红色共阳极数码管,可同时显示公历年、月、日、时、分、星期,以及农历月、日,还有秒点显示和整点报时、定时闹钟功能,使用220V市电供电,预留有备用电池座,外形尺寸为长21cm×宽14.5cm×厚3cm,最厚处6cm,适合放置在办公桌面上使用,具有很好的实用性。成品外观如图1所示。 图1 图2 原理简介 电路原理图如图2所示,为了读图方便,连线稍作了简化。从图中可以看出,IC1是一枚专用时钟芯片,Y1是32768Hz的晶振,为芯片提供时基频率信号,经过芯片内部处理后,输出各显示位的驱动信号,经过PNP(8550)型三极管做功率放大后驱动各数码管显示。芯片采用了动态扫描的输出

方式,由于人眼存在视觉暂留现象,且扫描速度比较快,因此看上去所有数码管都是在显示的。这种方式可以有效减少芯片的输出引脚数量,简化了线路,降低了功耗。 在电源部分中,整流二极管VD1~VD4组成了桥式整流电路,将变压器输出的交流电转换为直流电,经C6滤波后,送至三端稳压块7805,输出5V直流稳压电源,为电路供电。VD3和VD8组成互相隔离的供电电路,目的是在市电停电时,后备纽扣电池通过VD3,自动为芯片IC1提供后备电源,保证芯片计时数据不中断。同时由于VD8、VD9的存在,后备电池将不再向数码管供电,以节约后备电池的耗电量。由于芯片自身耗电较低,因此靠纽扣电池也可以维持芯片在很长时间里,内部计时不中断。当市电恢复后,7805输出经过VD8、VD9分别向芯片和数码管供电,由于DV3的存在,且纽扣电池电压为3V,低于7805输出的5V,因此纽扣电池将自动停止供电,7805输出也不会对纽扣电池充电。 VT9是唯一一只NPN(8050)型三极管,用于驱动喇叭,做为整点报时和定闹发声。LED10、LED14是用于秒点显示的发光二极管,LED11和LED12分别是整点报时显示和定闹显示的发光二极管,均为红色。 图3是万年历的全套散件的照片。表1是元器件清单。 图3 表1 元器件清单 序号元件名称参数元件数量序号元件名称参数元件数量 1 电阻10Ω 1 21 三极管8050 1 2 电阻33Ω8 22 三端稳压块7805 1 3 电阻47Ω 3 23 晶振32768Hz 1 4 电阻75Ω7 24 IC1软封装芯片 1 5 电阻100Ω 1 25 0.5’数码管红11 6 电阻150Ω8 26 0.8’数码管红 4

一个计算万年历的简单程序

一个计算万年历的简单程序 通常我们只知道生活当天的前后几天是星期几,即便是翻日历,也只能知道有限日期的星期数。那么有没有一种方法可以让我们知道任何一天是星期几呢?有,下面我将向大家介绍一种方法,用以编写万年历的程序。 首先我们必须约定一些法则,我们用Y、M、D分别表示年、月、日,用数字0-6分别表示星期日-星期六,这样我们就可以开始推导我们的公式了。 我们知道2002年9月1号为星期日,如果我们要想知道2002年9月10号为星期几,可以这样算:(0+(10-1))%7=(0+9)%7=2,即星期二。同样可算得2002年9月20号为:(0+(20-1))%7=(0+19)%7=5,即星期五。但是这样算需要把日期减1,不太方便,为了解决这个问题,我们可以假设每个月有一个0号,由于2002年9月1号为星期日,那么2002年9月0号为星期六,这样算9月10号,只需代入10既(6+10)%7=2。事实上,9月0号也就是8月31号,每个月0号的星期数实际上就是每个月1号的前一天的星期数。我把这个星期数称之为每个月的代码。有了这个代码,要算这个月任一天的星期数都好办了。 以上讨论的是一年中每个月的代码,事实上对于每年也有一个代码,这个代码就是每年1月0号(即1月1号的前一天)的星期数,也就是一月份的代码。如果我们能够找到每年的代码之间的关系,那么要计算万年历就易如反掌了。 (一)推算年的代码公式 我们都知道,平年一年有365天,即52周多1天。闰年为366天即52周多2天。我们先只考虑平年的情况。 假设第N年的代码为W,则第N+1年的代码为(W+1)%7,而第N+K年的代码则为(W+K)%7。这是因为从第N年到第N+K年共经过了K年,每过一年也就是过了52周余1天,经过K年也就是过了52*K周余K天,将多余的天数K加上第N年的代码W再对7取模,所得也就是第N+K年的代码了。 下面我们把闰年也考虑进来。判断闰年的规则是,能被4整除,并能被100和400同时整除的年份就是闰年。所以从第N年到第N+K年间共有K/4 -K/100+K/400个闰年,而每个闰年有52周余2天,要比平年多余了1天,即共多余了K/4-K/100+K/400天。我们应该把这些天也加进去,所以第N+K年的代码应为(W+K+K/4-K/100+K/400)%7。 这样子是不是就考虑完全了呢?并非如此,我们还有两点没考虑到。第一点是第N年是不是闰年。如果第N年是闰年的话,它本身就是52周余2天,而我们在上面却是把它当作平年来计算的,少算了1天,应加上。所以在第N年为闰年的时候上式应为 (W+(K+1)+K/4-K/100+K/400)%7。第二点是第N+K年是不是闰年。如果第N+K年是闰年,虽然它有52周余2天,但只有在算第N+(K+1)年的时候,才需要多加它那一天,而在算第N+K年的时候不需要多加这1天,因此我们必须将上式改为 (W+(K+1)+(K-1)/4-(K-1)/100+(K-1)/400)%7(注意千万不能改为 (W+(K+1)+(K/4-K/100+K/400-1))%7=(W+K+K/4-K/100+K/400)%7)。 由此我们可以得出当第N年为闰年时,第N+K年的代码计算式为: A=(W+(K+1)+(K-1)/4-(K-1)/100+(K-1)/400)%7 为了方便计算,我们可以取N为0,也就是假设公元元年的代码为W。因为公元元年也是闰年,符合上式,那么当我们输入的年份为Y时,此时就有K=Y,也就是说第Y年的代码为 A=(W+(Y+1)+(Y-1)/4-(Y-1)/100+(Y-1)/400)%7

电子万年历中公历农历互换算法研究

电子万年历中公历农历互换算法研究 [摘要]介绍了电子万年历中实现公历农历互换的一种实用算法。用4个字节的数据可以准确地描述任意一年与年历有关的信息,将需要实现公历农历互换的每一年的4个字节的数据有机存放在一起形成一个基本数据表。电子万年历中的计算机通过查询预先存储在计算机存储器里的基本数据表,得到转换需要的数据信息,根据转换要求和该算法提供的互换算法,从而实现公历农历的互换。该互换算法的优点是存储的数据量少,计算简便,实用性强。 [关键词]电子万年历;公历;农历;互换;算法 随着电子技术的发展,万年历目前已经不再局限于以书本形式出现。以电脑软件或者电子产品形式出现的万年历被称为电子万年历。与传统书本形式的万年历相比,电子万年历得到了越来越广泛的应用[1]。然而,目前一般的电子万年历仅能显示与公历有关的信息,而日常生活等方面往往离不开与农历有关的信息。为了使得电子万年历能更方便地显示更多的信息,笔者对电子万年历涉及到的常用信息处理算法进行了一些研究,提出了一种建表算法。这种建表算法与同类算法相比有以下优点:①需要存储的数据量小。②计算方法简便。③不仅可以显示公历,而且可以显示农历。④不仅可以显示当前日期,而且可以查询其他日期。下面以覆盖年度从1800年到2199年为例,详细介绍实现公历与农历之间相互转换的建表算法。 1 建立基本数据表 建立基本数据表的目的是实现公历与农历之间的相互转换。由于公历信息每年基本不变,而农历信息每年变化很大,因此,对于覆盖年度里的每一年,在基本数据表里主要存储与农历有关的数据:该年年份、该年闰月有无以及闰月的月份、该年各月的大小、从元旦到正月初一的天数(即岁首积日差[2])。 图1 基本数据表里每年的基本信息格式 在基本数据表里笔者用8位十六进制数D 7D 6D 5D 4D 3D 2D 1D 0 (4个字节)描绘一年的信息,其中每位十六进制数又可以用4 位二进制数(b 3b 2b 1b 0)表示。下面以一个具体的例子来说 明基本数据表里的数据格式(图1)。 1)D 7(b 3b 2b 1b 0)的前2两位b 3b 2表示百年值(譬如1982年所对应的百年值为19),后2位表示岁首积日差对15求商得到的商值(整数)。要实现覆盖年度1800到2199年的目标,只要前2位数(b 3b 2)对应的十进制数再加上18(十进制数)就能得到该年的百年值,即00代表1800年,01代表1900年,10代表2000年,11代表2100年。通过大量数据统计可得:对于任何年份,其岁首积日差均少于60日,而从1800年到2199年每一年的岁首积日差均不超过50日。因此,用D 7(b 3b 2b 1b 0)的后2位b 1b 0就能表示岁首积日差对15求商得到的商值,即00代表0日,01代表15日,10代表30日,11代表45日。本例中D 7表示该年年份为1900年到1999年中的某一年(具体由D 6和D 5决定),岁首积日差为30到44日中的某值(具体天数由D 0决定)。2)D 6(b 3b 2b 1b 0)前1位b 3表示该年闰月大小,后3位b 2b 1b 0表示该年所在百年内的年份值(譬如1982年所对应的百年内的年份值为82)对16求商得到的商值。高位b 3为1代表闰月小,为0代表无闰月或者闰月大;低3位b 2b 1b 0与百年内的年份值有以下对应关系,000代表0年,001代表16年,

用EXCEL制作新年万年历

用EXCEL制作新年万年历 新年伊始,制作一个新年万年历送给别人新年的祝福,这份心意是非常重要的。制作新年万年历有很多办法,但用Office的Excel表格制作你又试过没?下面给大家介绍用Excel 制作万年历。 今天我们介绍用Excel制作万年历的方法。这个新年万年历可以显示当月的月历,还可以随意查阅任何日期所属的月历,非常方便。如果你愿意,还可以让它在特殊的日子里显示不同的提醒文字,一起来试试吧! 本文所涉及到的函数有: 1、AND (logical1,logical2, ...) 2、DATE (year,month,day) 3、DAY (serial_number) 4、IF (Logical,Value_if_true,Value_if_false) 5、INT (number) 6、MONTH (serial_number) 7、NOW () 8、OR (logical1,logical2, ...) 1、启动EXCEL2003,新建一个工作表,取名保存(如万年历.xls),并在相应的单元格中,输入如图1所示的文本。

2、同时选中B1、C1、D1单元格,按“格式”工具栏上的“合并及居中”按钮,将其合并成一个单元格,并输入公式:=TODAY()。 选中B1(合并后的)单元格,执行“格式→单元格”命令,打开“单元格格式”对话框(如图2),在“数字”标签中的“分类”下面选中“日期”选项,再在右侧“类型”下面选中“二○○一年三月十四日”选项,“确定”退出,将日期设置成中文形式。 注意:TODAY()函数用于提取当前系统日期,请将系统日期一定要调整准确哟。 3、选中F1单元格,输入公式:=IF(WEEKDAY(B1,2)=7,"日",WEEKDAY(B1,2));选中H1单元格,输入公式:=NOW()。

中华万年历评测——简单粗暴有内涵的日历

中华万年历评测——简单粗暴有内涵的日历 作者:梦想屠夫 一个菜鸟的肺腑之言: 对于万年历我想大部分的人都会感到熟悉而陌生,特别是作为年轻的一代。熟悉的是,我们每天都会无意识的记起日历上的数字,陌生的是,年轻的我们已经渐渐的忽略了农历以及那些节气,于是“出门看黄历”这句话慢慢的也只在口头禅里面出现了。 还好,我遇见了中华万年历,简单的APP承载了不简单的内容。以下我来阐述使用中华万年历一小段时间以来我所领略到的各种鬼斧神工。 ------------------------------------------------------------------------------ 老煤油一枚,所持机型:魅族MX2 中华万年历版本:6. 1.0 ------------------------------------------------------------------------------ 【软件主要功能】 ●日历:节假日及特殊节日提示、农历节气、老黄历 ●天气状况:近5天天气状况趋势图、气温湿度、PM2.5污染物提示、各项生活指数提示 ●记录:日程表、记事以及待办事项记录提醒、最近节日倒计时、闹钟 ●订阅:可订阅时事热点、财经、美食、星座、旅行、健康养生等各项资讯频道●便民工具:查违章、找工作、找媳妇、租房子,医院挂号,还带抽签算卦等多般武艺 ●社交娱乐:生活圈功能,实时了解圈内圈外的生活动态,好比一个微信朋友圈诸多功能,不胜枚举。

话说百闻不如一见,那我就带大伙来瞧瞧我们这个简约而不简单的万年历…… ------------------------------------------------------------------------------ ▼1.【软件下载】 魅友们可以前往系统自带的应用中心去下载,也可以到360助手以及其他的应用中心去下载。软件容量不大,但是功能强悍。从下载量我们就不难看出使用人数的庞大,所以相信这是一枚好软件,值得推荐给大家。 ▼2.【登录开启云服务】 打开软件,首先看到的就是简约的界面,扁平化的风格,可以说是跟魅族fl yme系统门当户对。

C语言课程设计万年历 完整版

目录 一引言 (2) 二系统功能和数据说明 (3) 一)功能简介 (3) 二)程序中的数据说明 (3) 三程序总体设计及流程图 (4) 一)应用到的c语言 (4) 二)程序的总框架 (5) 四功能模块设计及调试 (5) 一)算法说明 (5) 1.总天数的算法 (5) 2.计算输入日期是星期几 (6) 3.对输入信息的汇总 (8) 4..界面的控制 (10) 二)调试结果 (11) 五程序清单 (12) 六结束语 (17)

一引言 通过大一上学期对C语言的学习,了解到了很多C语言的相关知识。学习的过程有很多困惑但是当自己能够独立的看懂,能过独立的完成一个简单的程序时,心中就会收获无限的喜悦和成就感。我可以里哟哦那个它看懂一些简单的程序,编写一些简单的计算程序,更多的是学会了一种思想——编程,它让我在去思考很多日常生活中的事物是怎么样通过一个个小小的函数实现功能的,激发我对探究的兴趣。 C语言是近年在国内外得到迅速推广应用的一种语言。C语言功能丰富,表达能力强,使用灵活方便,应用面广,目标程序效率高,可移植性好,既具有高级语言的优点,又具有低级语言的许多特点。因此,C语言特别适合于编写各种软件。 在这次的课程设计中我将把日常生活中最经常接触的——日期的查询利用C语言的程序编成一个简单的日历。通过这个小小的日历可以实现很多功能。在程序中你能看到很多熟悉的C语言关键字,同时也加入了很多自己课外了解到的一些关键字。在不断的调试中最终才获得最为完整的程序。接下来就是我的C 语言课程设计的具体内容来了

二系统功能和数据说明 (一)功能简介 在我们的日常生活中能接触到很多不同类型的日历,在日历上我们通常希望它能简介明了的给我们最想要的日期信息。在我的万年历当中,就是将日历,月历做的简单明了,很方便我们的使用。下面是它要实现的一些基本功能:用C语言编写万年历 1、输入年份,判断是否为闰年 2、输入年月日,判断改日为星期几 3、输入年份,打出12个月历,输入月份,打出该月的日历 4、要求用多个函数实现 [名称]万年历 [修改]1、对输入的日期进行容错处理 2、增加和修改为英文的月份和星期显示 3、采用指针形式的weeks和month数组 (二)程序中的数据说明 ①int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 这是定义的关于每个月天数的数组,根据大小月以及二月分的特殊情况将每个月的天数最为数组中的元素存入数组当中。其中days[1]=28,是将闰年二月的天数28天作为初始元素存入。在经过theWeek函数后就可以给days[1]中存入正确的月天数。 ②char *weeks[7] ={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; char *months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November",

用EXCEL制作新年万年历

用EXCEL制作新年万年历(修正版) 新年伊始,制作一个新年万年历送给别人新年的祝福,这份心意是非常重要的。制作新年万年历有很多办法,但用Office的Excel表格制作你又试过没?下面给大家介绍用Excel制作万年历。 今天我们介绍用Excel制作万年历的方法。这个新年万年历可以显示当月的月历,还可以随意查阅任何日期所属的月历,非常方便。如果你愿意,还可以让它在特殊的日子里显示不同的提醒文字,一起来试试吧! 本文所涉及到的函数有: 1、AND (logical1,logical2, ...) 2、DA TE (year,month,day) 3、DAY (serial_number) 4、IF (Logical,Value_if_true,Value_if_false) 5、INT (number) 6、MONTH (serial_number) 7、NOW () 8、OR (logical1,logical2, ...) 1、启动EXCEL2003,新建一个工作表,取名保存(如万年历.xls),并在相应的单元格中,输入如图1所示的文本。 2、同时选中B1、C1、D1单元格,按“格式”工具栏上的“合并及居中”按钮,将其合并成一个单元格,并输入公式:=TODAY()。 选中B1(合并后的)单元格,执行“格式→单元格”命令,打开“单元格格式”对话框(如图2),在“数字”标签中的“分类”下面选中“日期”选项,再在右侧“类型”下面选中“二○○一年三月十四日”选项,“确定”退出,将日期设置成中文形式。

注意:TODAY()函数用于提取当前系统日期,请将系统日期一定要调整准确哟。 3、选中F1单元格,输入公式:=IF(WEEKDAY(B1,2)=7,"日",WEEKDAY(B1,2));选中H1单元格,输入公式:=NOW()。 选中F1单元格,打开“单元格格式”对话框,在“数字”标签中的“分类”下面选中“特殊”选项,再在右侧“类型”下面选中“中文小写数字”选项,“确定”退出,将“星期数”设置成中文小写形式;选中H1单元格,打开“单元格格式”对话框,在“数字”标签中的“分类”下面选中“时间”选项,再在右侧“类型”下面选中一款时间格式,“确定”退出。 注意:①上述前面一个公式的含义是:如果(IF)当前日期(B1)是星期“7”(WEEKDAY(B1,2)=7),则在F1单元格中显示“日”,否则,直接显示出星期的数值(WEEKDAY(B1,2))。 ②上述第二个函数(NOW())用于提取当前系统日期和时间,也请将系统日期和时间调整准确。 4、在I1、I2单元格分别输入1900、1901,然后同时选中I1、I2单元格,用“填充柄”向下拖拉至I151单元格,输入1900—2050年份序列。 同样的方法,在J1至J12单元格中输入1—12月份序列。 5、选中D13单元格,执行“数据→有效性”命令,打开“数据有效性”对话框(如图3),按“允许”右侧的下拉按钮,选中“序列”选项,在“来源”下面的方框输入:=$I$1:$I$151,“确定”退出。 同样的操作,将F15单元格数据有效性设置为“=$J$1:$J$12”序列。 注意:经过这样的设置以后,当我们选中D15(或F15)单元格时,在单元格右侧出现一个下拉按钮,按此下拉按钮,即可选择年份(或月份)数值,快速输入需要查询的年、月值。 6、选中A2单元格(不一定非得是A2哟),输入公式:=IF(F13=2,IF(OR(D13/400=INT(D13/400),AND(D13/4=INT(D13/4),D13/100=INT(D13/100))),29,28),IF(OR(F13=4,F13=6,F13=9,F13=11),30,31)),用于获取查询“月份”所对应的天数(28、29、30、31)。 注意:上述函数的含义是:如果查询“月份”为“2月”(F13=2)时,并且“年份”数能被400整除[D13/400=INT(D13/400)],或者(OR)“年份”能被4整除,但不能被100整除[AND(D13/4=INT(D13/4),D13/100 INT(D13/100))],则该月为29天(也就是我们通常所说的“闰年”),否则为28天。如果“月份”不是2月,但是“4、6、9、11”月,则该月为30天。其他月份天数为31天。 7、选中B2单元格,输入公式:=IF(WEEKDAY(DATE($D$13,$F$13,1),2)=B3,1,0)。再次选中B2单元格,用“填充柄”将上述公式复制到C2—H2单元格中。 注意:①上述B2公式的含义是:如果“查询年月”的第1天是星期“7”(WEEKDAY(DATE)($D$13,$F$13,1),2)=B3)时,在该单元格显示“1”,反之显示“0”),为“查询年月”获取一个对

万年历星期的算法(C语言)

万年历星期的算法(C语言) #include code unsigned char WeekTab[] = { //闰年月星期表 (3 << 5) + 31,//1月 (6 << 5) + 29,//2月 (0 << 5) + 31,//3月 (3 << 5) + 30,//4月 (5 << 5) + 31,//5月 (1 << 5) + 30,//6月 (3 << 5) + 31,//7月 (6 << 5) + 31,//8月 (1 << 5) + 30,//9月 (4 << 5) + 31,//10月 (0 << 5) + 30,//11月 (2 << 5) + 31 //12月 }; /*------------2000年~2099年星期算法----------*/ unsigned char WeekDay20(unsigned char y, unsigned char m, unsigned char d) { unsigned char week, day; day = WeekTab[m - 1]; //月表 week = day >> 5; //月星期数 day &= 0x1f; //月天数 if ((m < 3) && (y & 0x03)) { //平年 if (m == 2) day--; //平年月天数 week++; //平年月表+1 } y = y + (y >> 2); //年+年/4 week = (week + y + d + 2) % 7; //(星期=年+年/4+月表+2日)%7 return (week << 5) | day; //返回星期和月天数 } /*--------------0000年~9999年星期算法------------*/ unsigned char WeekDay(unsigned char c, unsigned char y, unsigned char m, unsigned char d) { unsigned char week, day; c &= 0x03; //百年%4 c = c | (c << 2); //百年%4*5 day = WeekTab[m - 1]; //月表 week = day >> 5; //月星期数

用Excel怎样制作万年历

可以把Excel表格内容设置为桌面背景么? 悬赏分:10 - 解决时间:2007-2-15 08:32 由于经常要查一个Excel表,就想如果把它设置为桌面背景就会很方便了,求教高手,怎么做才能办到? 提问者:firtre - 三级 最佳答案 文件-另存为网页-在桌面上点右键-属性-桌面-自定义桌面-web-钩上就搞定了 用Excel怎样制作万年历 Excel 2010-02-07 15:18:53 阅读578 评论29 字号:大中小 准备工作,制作如下电子表格:

第一步:在C2中输入=TODAY()回车。TODAY()函数用于提取当前系统日期。 第二步:在F2中输入=IF(WEEKDAY(C2,2)=7,"日",WEEKDAY(C2,2)) 回车。 第三步:在H2中输入 =NOW() 回车。NOW()用于提取当前系统时间。 第四步:在D14中设置下拉菜单,数值为1900—2029。参见“怎样制作下拉菜单”

第五步:在F14中设置下拉菜单,数值为1—12。

将查询日期调为当前日期,如下图:

第六步:在A3中输入: =IF(F14=2,IF(OR(D14/400=INT(D14/400),AND(D14/4=INT(D14/4),D14/100<>INT(D14/100))),29, 28),IF(OR(F14=4,F14=6,F14=9,F14=11),30,31))回车。 第七步:B3中输入=IF(WEEKDAY(DATE($D$14,$F$14,1),2)=B4,1,0)回车。选中B3向右复制公式 至H3。 第八步:B6中输入=IF(B3=1,1,0)回车。 第九步:在B7中输入=H6+1回车,选中B7,向下复制公式至B9。 第十步:在B10中输入=IF(H9>=A3,0,H9+1)回车。 第十一步:在B11中输入=IF(H10>=A3,0,IF(H10>0,H10+1,0))回车。 第十二步:在C6中输入=IF(B6>0,B6+1,IF(C3=1,1,0))回车。 第十三步:在C7中输入=B7+1回车。 第十四步:选中C7向下复制公式至C9。 第十五步:在C10中输入=IF(B10>=$A$3,0,IF(B10>0,B10+1,IF(C6=1,1,0)))回车。 第十六步:选中C6,向右复制公式至H6。 选中C7,向右复制公式至H7。 选中C8,向右复制公式至H8。

c语言课程设计报告--万年历,最详细

C语言课程设计报告 -----万年历 设计人:贾伟涛 学号:2013010912 班级:13电信应电班 指导老师:张伟 日期:2014年6月9日

内容提要 通过大一下学期对C语言的学习,了解到了很多C语言的相关知识。学习的过程虽然有很多困惑,但是当自己能够独立的看懂和独立的完成一个简单的程序时,心中就会收获无限的喜悦和成就感。我虽然可以看懂一些简单的程序,编写一些简单的计算程序,更多的是学会了一种思想——编程,它让我在去思考很多日常生活中的事物是怎么样通过一个个小小的函数实现功能的,激发我对c语言的兴趣。 C语言是近年在国内外得到迅速推广应用的一种机器语言。C语言功能丰富,表达能力强,使用灵活方便,应用面广,目标程序效率高,可移植性好,既具有高级语言的优点,又具有低级语言的许多特点。因此,C语言特别适合于编写各种软件。 在这次的课程设计中我将把日常生活中最经常接触的——日历的查询,利用C语言的程序编成一个简单的万年历查询系统。通过这个小小的系统可以实现很多功能。在程序中你能看到很多熟悉的C语言关键字,同时也加入了很多自己课外了解到的一些关键字。在不断的调试中最终才获得最为完整的程序。接下来就是我的C语言课程设计的具体内容来了,大家拭目以待吧!

目录 一、系统功能和数据说明----------------------- 二、问题分析--------------------------------- 三、程序总体设计及功能结构框图--------------- 四、程序流程图------------------------------- 五、源程序代码------------------------------- 六、使用说明--------------------------------- 七、个人心得--------------------------------- 八、参考文献---------------------------------

STM32实现万年历

STM32学习笔记一竹天笑 实现的功能: 1、日历功能。 2、数字和模拟时钟功能。 图1(为LCD截屏保存在SD卡中的图像) 最终界面如下,但还存在不少漏洞。1、没有更改时间的设置;2、只有节气显示没有节假日显示3、背景不是用uCGUI画的,是在PS中画好然后存在SD卡中,然后显示的BMP 格式图像。 要点分析: 1、STM32自带了RTC时钟计数器,从0开始计数到232。每一个计数代表秒计数,每六十个计数代表分计数,以此类推。24(小时)*60(分钟)*60(秒钟)=86400代表一天的计数时间。假设当前计数为count,count/86400得到计数的天数,根据这个得到年月日。Count%86400得到时分秒。 2、一些根据1中得到的年月日时分秒,进行计算的程序有:阳历转阴历,闰年判断,节气判断,星期几计算,当前月有多少天等等。 3、模拟时钟的绘制:时钟指针运动算法、屏幕重绘方法、RTC消息、画笔/画刷等。指针运动算法和屏幕重绘方法是本程序主要难点所在。(以下参照百度文库之模拟时钟)不论何种指针,每次转动均以π/30弧度(一秒的角度)为基本单位,且都以表盘中心为转动圆心。计算指针端点(x, y)的公式如下:

x =圆心x坐标+ 指针长度* cos (指针方向角) y =圆心y坐标+ 指针长度* sin (指针方向角) 注意,指针长度是指自圆心至指针一个端点的长度(是整个指针的一部分),由于指针可能跨越圆心,因此一个指针需要计算两个端点。 由于屏幕的重绘1秒钟一次,如果采用全屏删除式重绘则闪烁十分明显,显示效果不佳。本程序采用非删除式重绘,假定指针将要移动一格,则先采用背景色(这里是白色)重绘原来指针以删除原来位置的指针,再采用指针的颜色在当前位置绘制指针(如果指针没有动,则直接绘制指针,此句在程序中被我删除,具体原因,为数据截断导致一些误差)。 另外,秒表为RTC一秒钟定时计数。 程序分析: uCGUI+uCOS,一共三个任务:主处理任务、触摸屏任务、秒更新任务。 void App_UCGUI_TaskCreate (void) { CPU_INT08U os_err; os_err = os_err; Clock_SEM=OSSemCreate(1); /位置设定 GUI_SetFont(&GUI_Font6x8); 3.1415926f=-20*cos(*30+90)*DEG2RAD)+264; =-20*sin(*30+90)*DEG2RAD)+170; =-2*cos(*30+270)*DEG2RAD)+264; =-2*sin(*30+270)*DEG2RAD)+170; ,m_OldHour[0].y, m_OldHour[1].x,m_OldHour[1].y); GUI_SetColor(GUI_RED); ,m_Hour[0].y, m_Hour[1].x,m_Hour[1].y);

万年历的算法

摘自: 星期、干支、二十八宿计算公式打印本页关闭本窗口 1. 求星期公式 星期=[5+A(实际天数)] mod 7 2. 干支计算公式 六十甲子干支序号,从1->59->0。 六十甲子干支序号=[23+A(实际天数)] mod 60 3. 二十八宿计算公式 二十八宿序号=[23+A(实际天数)] mod 28 4. 实际天数A的计算 A=B(基本天数)+C(闰日天数) B=(计算年-1)*365+(要计算到年的月日天数) 例:1984年2月1日的基本天数B=(1984-1)*365+(31+1)=723827(天), 其中,31是1月为31天,1为2月1日为1天。 公元308年8月28日的基本天数 B=(308-1)*365+(31+28+31+30+31+30+31+27)=112055+239=112294(天) 这里的(要计算到年的月日天数),用的是公历,月日天数的规则我好 象小学就学过了。哈哈…… C=(计算年-1) div 4 -误差修正值+ fixValue2 fixValue2为0或者1。常值为0,当年数为闰年(公历闰年法)之中的3月 1日之后的为1。 误差修正值推算: 公元元年1月1日至1582年10月14日为0。 1582年10月15日至1699年12月31日为10。 从1701年1月1日起每增加一个世纪累加1,但能被400除尽的世纪不累 加1。此方法推算即可。 --有一个问题,1700年这一年的修正值应为多少呢?算法中正好没有 讲到,但看来应该是10。 例1701年1月1日起误差值为11,而1801年1月1日起误差修正值为12,而1901年1月1日起误差修正值为13, 但2001年误差修正值仍为13,因为2000年能被400整除,故不累加。而2101年1月1日起误差修正值为14。 5. 实例:1998.3.15的星期、干支与二十八宿 B=(1998-1)*365+(31+28+15)=728979 C=(1998-1) div 4 - 13 + 0 = 486 A=B+C=728979+486=729465 星期序号=(5+729465) mod 7=0,即为星期日 干支序号=(13+729465) mod 60=58,即为辛酉

单片机万年历程序..

单片机万年历程序 #include //调用单片机头文件 #define uchar unsigned char //无符号字符型宏定义变量范围0~255 #define uint unsigned int //无符号整型宏定义变量范围0~65535 #include "eeprom52.h" #include "nongli.h" bit flag_200ms ; bit flag_100ms ; sbit beep = P3^7; //蜂鸣器定义 bit flag_beep_en; uint clock_value; //用作闹钟用的 sbit dq = P3^1; //18b20 IO口的定义 uint temperature ; //温度变量 uchar flag_nl; //农历阳历显示标志位 uchar menu_1,menu_2; uchar key_time,flag_value; //用做连加的中间变量 bit key_500ms ; uchar n_nian,n_yue,n_ri; //农历显示的函数

#include "ds1302.h" #include "lcd1602.h" /******************把数据保存到单片机内部eeprom中******************/ void write_eeprom() { SectorErase(0x2000); byte_write(0x2000, fen1); byte_write(0x2001, shi1); byte_write(0x2002, open1); byte_write(0x2058, a_a); } /******************把数据从单片机内部eeprom中读出来*****************/ void read_eeprom() { fen1 = byte_read(0x2000); shi1 = byte_read(0x2001); open1 = byte_read(0x2002); a_a = byte_read(0x2058); } /**************开机自检eeprom初始化*****************/ void init_eeprom() { read_eeprom(); //先读 if(a_a != 1) //新的单片机初始单片机内问eeprom { fen1 = 3;

手算万年历

一只左手即是万年历 掐指一算即知吉凶”,学过算命卜卦的人对吉凶的推算应该没多大问题,但要做到掐指就能算并非一照一夕的事(除相术外)。 因为所有算法基本上都要用到干支历,所以你看很多算命算卦的都要有本万年历。其实,我们的左手就是一本万年历,许多人不知道,所以不会推算。当然,这也是算命达到出神入化的关键技术,你想如果什么也不用,就能把四柱在心中排出,对求测者来说更加神奇。现把一种最简单的掐指法介绍出来。 (此法在网上公布了数个小时,因为是秘籍,所以被删掉。其中日柱掐指之法并非真法,并有错误在其中,真法没传,真法不用计算,不用万年历,只需掐指即可推出。想学者,可以拿秘籍来交流,只求风水方面的,我所掌握的除外) 现举一例说明:(阳历换算干支) 随便说一个时间,2018年3月10日早8点:左手,拇指掐“子”上后退3个两位(3为8,9,10三个)为“午”。接着从“午”上顺掐5位(5为甲、乙、丙、丁、戊5位),得“戌”位即“戊戌”干支。此年柱。 月柱,年干“戊”,“壬子”起,这也无须记,也可以掐指,在左手上,大拇指在“甲己”位上念“甲乙”,顺推,到“戊”上为“壬”。所以“壬子”起,到“卯”为“乙卯”。此月柱。 日柱,干从"庚"顺数,第9位为"戊",余2,所以是"戊的相合干"癸".支从"子"数,依次为"子"、“酉”、“午”、“卯”第9位还为“子”,因为余2,下一步,“子”冲“午”前一位为“巳”。所以得“癸巳”。然后从“癸”起数9位为“辛”,从“巳”起9位为“丑”。所以,日柱为“辛丑”。 时柱,我想大家都会吧,早8为辰时,日起时法,“子”上数“戊”到“辰”为“壬”,即“壬辰”时。 好了,四柱为:戊戌乙卯辛丑壬辰。 这是个例操作过程,不是通用方法。掌握通用方法,熟练后,比查万年历要快。因为有些步骤大脑可以快速跳过。瞬间得到结果。 本人看过多种掐指算干支的秘籍,其实都要大量背一些口诀,并不诀,而这种方法,只需记住两个数,进行一次简单的两位数减法运算(心算完全可以做到),和一次两位除一位数的除法运算(心算完全可以做到)外,完全是掐指得到的结果。

日历2020日历黄道吉日

日历2020日历黄道吉日 导读:黄道吉日的选择已经与我们的生活息息相关,不管你是要出行,要开业,要结婚,要入宅,或者是要动土也好,都离不开查询黄道吉日。选择最适合的黄道吉日做事,不仅能利于事情更好进行,更是给自己一个好的预示和运势。那么,2020年黄道吉日有哪些呢?2020年每个月哪几天是黄道吉日呢?以下是万年历小编带来的2020年黄道吉日一览表,快点来看。 2020年黄道吉日一览表 2020年1月黄道吉日一览 公元2020年1月2日,星期四,农历二零一九年十二月(大)初八,冲狗(戊戍)煞南,黄道定日 公元2020年1月5日,星期日,农历二零一九年十二月(大)十一,冲牛(辛丑)煞西,黄道危日 公元2020年1月6日,星期一,农历二零一九年十二月(大)十二,冲虎(壬寅)煞南,黄道危日 公元2020年1月9日,星期四,农历二零一九年十二月(大)十五,冲蛇(乙巳)煞西,黄道开日 公元2020年1月12日,星期日,农历二零一九年十二月(大)十八,冲猴(戊申)煞北,黄道除日

公元2020年1月16日,星期四,农历二零一九年十二月(大)廿二,冲鼠(壬子)煞北,黄道执日 公元2020年1月18日,星期六,农历二零一九年十二月(大)廿四,冲虎(甲寅)煞南,黄道危日 公元2020年1月21日,星期二,农历二零一九年十二月(大)廿七,冲蛇(丁巳)煞西,黄道开日 公元2020年1月24日,星期五,农历二零一九年十二月(大)三十,冲猴(庚申)煞北,黄道除日 公元2020年1月27日,星期一,农历二零二零年正月(小)初三,冲猪(癸亥)煞东,黄道定日 公元2020年1月30日,星期四,农历二零二零年正月(小)初六,冲虎(丙寅)煞南,黄道危日 公元2020年1月31日,星期五,农历二零二零年正月(小)初七,冲兔(丁卯)煞东,黄道成日 2020年2月黄道吉日一览 公元2020年2月2日,星期日,农历二零二零年正月(小)初九,冲蛇(己巳)煞西,黄道开日 公元2020年2月10日,星期一,农历二零二零年正月(小)十七,冲牛(丁丑)煞西,黄道执日 公元2020年2月12日,星期三,农历二零二零年正月(小)十九,冲兔(己卯)煞东,黄道危日

C语言实训题目设计报告 万年历

C语言实训题目设计报告:万年历系统 1、题目设计: 设计一个万年历系统 功能要求: (1)从2000年开始,用户输入年份与月份,将显示出该年该月份的日历,对应的星期。 (2)用户输入年份,将显示该年的日历 (3)注意闰年情况 显示格式要求如下: (1)第一行显示月份(中英文都可以) (2)下一行显示星期,从周日到周六,中英文都可以 (3)下一行开始显示日期从1号开始,并按其是星期几实际情况与上面的星期数垂直对齐 (4)程序输出菜单,用户按照提示操作,最终得到计算结果。 2、问题分析: 该程序可大致分成主菜单、年历、月历3个部分,并且还有判断是否为闰年、月份的天数、该月第一天为周几三个小模块,并可由年历、月历调用,年历、月历可由主菜单调用。最后可以考虑一下界面的优化和输入错误等小问题。 3、算法设计: 主菜单部分:用户输入选项,用一个switch语句来进行接下来的任务,其中有一个选项是用来退出的。在进行到程序结尾的时候用goto语句来实现回到函数最开始的目的。 月历部分:从键盘接收年份和月份,通过小函数来获得本月的天数和本月一号是周几,从而在屏幕上输出月历。在到周末的时候换行。 年历部分:大体思路和月历相似,只是多用了一个for循环,使得月份从一月一直到十二月(其实这部分我是复制的月历部分的)。 判断闰年部分:输入年份,输出1或0。 判断天数部分:输入年份,月份,输出天数。其中有调用闰年的函数。 判断周几部分:输入年,月,日,输出是周几的信息。 4、程序源代码: #include #include #include int ifren(int year)//判断是否是闰年 { if(year%4==0&&year%100!=0||year%400==0) return 1; else return 0; } int monthday(int month,int year)//判断这个月有多少天

万年历计算方法

万年历计算方法 1。平年365天(52周+1天),闰年366天(52周+2天)。平年2月28天,闰年2月29天。 由于公元1月1日设为星期六,故3月1日为星期三。——注意这个“三” 为使算法达到最简,故本算法以“星期”为计算单位。且选3月1日为基月。 2。每400年整一闰,或每4年且不为百年的一闰。(原因:地球绕太阳一周的时间是365天5小时46秒,为了使一年的天数为整数,将一年的天数定为365天,余下的时间积累起来,四年就是23小时15分4秒,将近一天,把这一天加在某年的二月而成29天,该年称为闰年,其它年称为平年。但四年加一天又多用了44分56秒,这个数积满400年为三天。因此400年中只能有97个闰年,所以凡能被400整除,或不能被100整除但能被4整除的年份为闰年。) 所以百年%4=0闰或(年%4=0并且年<>0)闰。 3。每 4年(3个平年+1个闰年)共208周+5天——注意这个“5天” 每百年共100*(208周+5天)-1天=5217周+5天——注意这个“5天”(整百年暂设为平年) 每400年共4*(5217周+5天)+1天(整400年闰)=20871周+0天——注意这个“0天”和 “1天”(4个整百年只有一个闰年) 即400年一轮回!(原来万年历400年前是一家) 蔡勒(Zeller)公式 历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和一些分段计算公式),其中最著名的蔡勒(Zeller)公式 即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 公式中的符号含义如下,w:星期;c:世纪-1;y:年(两位数);m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算);d:日;[ ]代表取整,即只要整数部分。(C是世纪数减一,y是年份后两位,M是月份,d是日数。1月和2月要按上一年的13月和 14月来算,这时C和y均按上一年取值。) 算出来的W除以7,余数是几就是星期几。如果余数是0,则为星期日。 以2049年10月1日(100周年国庆)为例,用蔡勒(Zeller)公式进行计算,过程如下: 蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 =49+[49/4]+[20/4]-2×20+[26× (10+1)/10]+1-1

相关主题
文本预览
相关文档 最新文档