搜档网
当前位置:搜档网 › 西电电院课程设计日历显示

西电电院课程设计日历显示

班级 1302041

学号 130********

课程设计报告

题目编程实现带农历的日历

学院电子工程学院

专业探测制导与控制技术

学生姓名陈xx

指导教师曹向海

课程设计(报告)任务书

学生姓名陈xx指导教师曹向海职称副教授

学生学号130******** 专业探测制导与控制技术

题目带农历的日历显示

任务与要求

输入任一年份,显示该年所有月份日期,以及对应的星期,并尝试计算出对应的阴历

开始日期2016年 12 月 26 日完成日期2017 年 1月9 日课程

设计所在单位电子工程学院 2017年 1 月 9 日

摘要

本论文介绍了日历显示的全部完整的流程算法和基本思想,详细分析了日历显示中关键难点技术问题,包括了如何将日期转换为其对应的星期,如何将公历日期转换为农历日期,如何将某个月份按照日历格式输出的输出控制。

日历与日程任务紧密相连,密不可分。日历可以考勤计算的依据,在MPS、MRP中基于提前期计算主生产计划、作业计划时用于确定开工日期、完工日期的依据;计算工作中心产能负荷时的日期基础;资金实现日期的认定。在广大人民群众的日常生产生活中也是应用广泛,它提供了出行安排,指导农业生产和社会生活的方方面面。本课题中使用

Visual C++6.0编译平台实现日历显示的基本功能。

关键词:日历农历 C语言

页页

Abstract

This paper introduces the process of the algorithm and the basic idea of the calendar display complete, detailed analysis of the key technical problems in the calendar display, including how to convert to the corresponding day of the week, how will the lunar calendar date conversion date, how will a month calendar according to the output format of the output control.

Calendars are closely linked to the schedule. The calendar can be calculated on the basis of attendance, in MPS, MRP lead time calculation based on the main production plan and operation plan is used to determine the date of commencement and completion of the basis; calculate the date base work center capacity load; funds implementation date determination. In the broad masses of the people's daily production and life is also widely used, it provides travel arrangements to guide all aspects of agricultural production and social life. This topic uses the Visual C++6.0 compiler platform to achieve the basic functions of the calendar display.

Key words: calendar lunar C language

页页

目录

第一章引言

1.1 本课题研究的目的及意义 (4)

1.2 本文所研究的主要内容及所做工作 (5)

第二章基础原理

2.1星期转换的公式 (6)

2.2公式的推导过程 (6)

第三章方案设计

3.1公历转换农历的基本思想 (17)

3.2算法流程图 (18)

第四章控制台输出日历格式

4.1 算法基本思想 (19)

4.2算法流程图 (19)

结果与总结 (19)

参考文献 (23)

页页

页页

第一章引言

1.1 本课题研究的目的及意义

在当今和未来的信息化社会中,人们对于时间的追求越来越近乎执着,时间单位更是以纳秒计,日历作为一种传统的记载时间日程等相关信息的出版物,在社会生产生活中发挥着越来越重要的作用。日历当中的日期信息可以帮助人们规划日程安排,提供出行及工作考勤的数据支撑,农历信息更是可以为广大群众提供农业生产的指导,我国的传统节假日都是以农历日期安排,而如今年轻人大都习惯用公历纪年,慢慢的遗忘的我们的传统阴历纪年方式,因此制作日历同时也激发了我本人对传统文化的热爱增加了相关知识的了解。

日历通常包括的基本信息有:公历日期,农历日期,星期。其中,公历是现在国际通用的历法,又译格列历、国瑞历、额我略历、格列高利历、格里高利历等,公历的标准名称为格里高利历,是现在国际通用的历法,是一种阳历,以地球绕行太阳一周为一年。阳历是太阳历的简称,这种历法与地球环绕太阳的周年运动有关,与月相无关。

农历是我国传统历法,又称夏历、中历、国历、俗称阴历。定月的方法是用朔望月周期给出,朔所在日为初一,朔望月长约29天半,所以农历大月30天,小月29天。农历平年有十二个月,全年354天或355天,闰年为十三个月,其中某一月为闰月,月名依前一月名而定,如前月是八月,闰月则为闰八月。闰年全年383天或384天。设置闰月的方法是:农历月份中无“中气”的月份则是闰月。农历又根据太阳的位置,把太阳年分成二十四个节气,反映寒冷暑热的气候变化,以便家事活动,所以农历实为阴阳历。

星期在中国古代称七曜。七曜在中国夏商周时期,是指日、月、及五大行星等七个主要星体,是当时天文星象的重要组织成份。后来借用作七天为一周的时间单位,故称星期。星期,又叫周或礼拜,是古巴比伦人创造的一个时间单位,也是现在制定工作日、休息日的依据[4]。

1.2 本文所研究的主要内容及所做工作

本文对日历的农历转换、星期获取、日历格式输出进行了研究,并在Visual C++6.0平台上编译调试并且顺利实现了相关功能。内容主要包括:

1、指定公历日期的星期获取;

2、详细介绍公历日期转换成农历的算法和思想;

3、控制输出格式,达到指定月份的日历显示效果。

4、Visual C++6.0平台实现效果展示

第二章基础原理

2.1星期转换的公式

历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和一些分段计算公式),其中最著名的是蔡勒(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)公式进行计算,过程如下[3]:

蔡勒(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

=49+[12.25]+5-40+[28.6]

=49+12+5-40+28

=54 (除以7余5)

即2049年10月1日(100周年国庆)是星期5。

不过,以上公式只适合于1582年10月15日之后的情形(当时的罗马教皇将恺撒大帝制订的儒略历修改成格里历,即今天使用的公历)。

2.2公式的推导过程

星期制度是一种有古老传统的制度。据说因为《圣经?创世纪》中规定上帝用了六天时间创世纪,第七天休息,所以人们也就以七天为一个周期来安排自己的工作和生活,而星期日是休息日。从实际的角度来讲,以七天为一个周期,长短也比较合适。所以尽管中国的传统工作周期是十天(比如王勃《滕王阁序》中说的“十旬休暇”,即是指官员的工作每十日为一个周期,第十日休假),但后来也采取了西方

的星期制度。

在日常生活中,我们常常遇到要知道某一天是星期几的问题。有时候,我们还想知道历史上某一天是星期几。通常,解决这个方法的有效办法是看日历,但是我们总不会随时随身带着日历,更不可能随时随身带着几千年的万年历。假如是想在计算

机编程中计算某一天是星期几,预先把一本万年历存进去就更不现实了。这时候是

不是有办法通过什么公式,从年月日推出这一天是星期几呢?

答案是肯定的。其实我们也常常在这样做。我们先举一个简单的例子。比如,知道了2004年5月1日是星期六,那么2004年5月31日“世界无烟日”是星期几就不难推

算出来。我们可以掰着指头从1日数到31日,同时数星期,最后可以数出5月31日是星期一。

其实运用数学计算,可以不用掰指头。我们知道星期是七天一轮回的,所以5月1日是星期六,七天之后的5月8日也是星期六。在日期上,8-1=7,正是7的倍数。同样,5月15日、5月22日和5月29日也是星期六,它们的日期和5月1日的差值分别是14、21

和28,也都是7的倍数。那么5月31日呢?31-1=30,虽然不是7的倍数,但是31除以7,余数为2,也就是说,5月31日的星期是在5月1日的星期之后两天。星期六之后的两天正是星期一。这个简单的计算告诉我们计算星期的一个基本思路:首先,先要知道在想算的日子之前的一个确定的日子是星期几,拿这一天做为推算的标准,也就是相当于一个计算的“原点”。其次,知道想算的日子和这个确定的日子之间相差多少天,用7除这个日期的差值,余数就表示想算的日子的星期在确定的日子的星期之后多少天。如果余数是0,就表示这两天的星期相同。显然,如果把这个作为“原点”的日

子选为星期日,那么余数正好就等于星期几,这样计算就更方便了[3]。

但是直接计算两天之间的天数,还是不免繁琐。比如1982年7月29日和2004年5月

1日之间相隔7947天,就不是一下子能算出来的。它包括三段时间:一,1982年7月29日以后这一年的剩余天数;二,1983-2003这二十一个整年的全部天数;三,从2004

年元旦到5月1日经过的天数。第二段比较好算,它等于21*365+5=7670天,之所以要

加5,是因为这段时间内有5个闰年。第一段和第三段就比较麻烦了,比如第三段,需要把5月之前的四个月的天数累加起来,再加上日期值,即31+29+31+30+1=122天。

同理,第一段需要把7月之后的五个月的天数累加起来,再加上7月剩下的天数,一共是155天。所以总共的相隔天数是122+7670+155=7947天。

仔细想想,如果把“原点”日子的日期选为12月31日,那么第一段时间也就是一个整年,这样一来,第一段时间和第二段时间就可以合并计算,整年的总数正好相当于两个日子的年份差值减一。如果进一步把“原点”日子选为公元前1年12月31日

(或者天文学家所使用的公元0年12月31日),这个整年的总数就正好是想算的日子

的年份减一。这样简化之后,就只须计算两段时间:一,这么多整年的总天数;二,想算的日子是这一年的第几天。巧的是,按照公历的年月设置,这样反推回去,公元前1年12月31日正好是星期日,也就是说,这样算出来的总天数除以7的余数正好是星期几。那么现在的问题就只有一个:这么多整年里面有多少闰年。这就需要了解公历的置闰规则了。

我们知道,公历的平年是365天,闰年是366天。置闰的方法是能被4整除的年份

在2月加一天,但能被100整除的不闰,能被400整除的又闰。因此,像1600、2000、2400年都是闰年,而1700、1800、1900、2100年都是平年。公元前1年,按公历也是

闰年。

因此,对于从公元前1年(或公元0年)12月31日到某一日子的年份Y之间的所有

整年中的闰年数,就等于[(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400],[...]表示只取整数部分。第一项表示需要加上被4整除的年份数,第二项表示需要去掉被100整除的年份数,第三项表示需要再加上被400整除的年份数。之所以Y要减一,这样,我们就得到了第

一个计算某一天是星期几的公式:

W = (Y-1)*365 + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D. (1) 其中D是这个日子在这一年中的累积天数。算出来的W就是公元前1年(或公元0年)12月31日到这一天之间的间隔日数。把W用7除,余数是几,这一天就是星期几。比如我们来算2004年5月1日:

W = (2004-1)*365 + [(2004-1)/4] - [(2004-1)/100] + [(2004-1)/400]

+(31+29+31+30+1)= 731702,

731702 / 7 = 104528……6,余数为六,说明这一天是星期六。这和事实是符合的。

上面的公式(1)虽然很准确,但是计算出来的数字太大了,使用起来很不方便。

仔细想想,其实这个间隔天数W的用数仅仅是为了得到它除以7之后的余数。这启发

我们是不是可以简化这个W值,只要找一个和它余数相同的较小的数来代替,用数论

上的术语来说,就是找一个和它同余的较小的正整数,照样可以计算出准确的星期数。

显然,W这么大的原因是因为公式中的第一项(Y-1)*365太大了。其实,

(Y-1)*365 = (Y-1) * (364+1)

= (Y-1) * (7*52+1)

= 52 * (Y-1) * 7 + (Y-1),

这个结果的第一项是一个7的倍数,除以7余数为0,因此(Y-1)*365除以7的余数

其实就等于Y-1除以7的余数。这个关系可以表示为:

(Y-1)*365 ≡ Y-1 (mod 7).

其中,≡是数论中表示同余的符号,mod 7的意思是指在用7作模数(也就是除数)的情况下≡号两边的数是同余的。因此,完全可以用(Y-1)代替(Y-1)*365,这样我们

就得到了那个著名的、也是最常见到的计算星期几的公式:

W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D. (2) 这个公式虽然好用多了,但还不是最好用的公式,因为累积天数D的计算也比较

麻烦。是不是可以用月份数和日期直接计算呢?答案也是肯定的。我们不妨来观察

一下各个月的日数,列表如下:

如果把这个天数都减去28(=4*7),不影响W除以7的余数值。这样我们就得到另一

张表:

仔细观察的话,我们会发现除去1月和2月,3月到7月这五个月的剩余天数值是

3,2,3,2,3;8月到12月这五个月的天数值也是3,2,3,2,3,正好是一个重复。相应的累积

天数中,后一月的累积天数和前一月的累积天数之差减去28就是这个重复。正是因

为这种规律的存在,平年和闰年的累积天数可以用数学公式很方便地表达:

D = d;(当M=1)

D = { 31 + d;(当M=2) (3)

D =[ 13 * (M+1) / 5 ] - 7 + (M-1) * 28 + d + i.(当M≥3)

其中[...]仍表示只取整数部分;M和d分别是想算的日子的月份和日数;平年i=0,闰年 i=1。对于M≥3的表达式需要说明一下:[13*(M+1)/5]-7算出来的就是上面第二

个表中的平年累积值,再加上(M-1)*28就是想算的日子的月份之前的所有月份的总

天数。这是一个很巧妙的办法,利用取整运算来实现3,2,3,2,3的循环。比如,对2004

年5月1日,有:

D = [ 13 * (5+1) / 5 ] - 7 + (5-1) * 28 + 1 + 1

= 122,这正是5月1日在2004年的累积天数。

假如,我们再变通一下,把1月和2月当成是上一年的“13月”和“14月”,不仅仍然符合这个公式,而且因为这样一来,闰日成了上一“年”(一共有14个月)的最后一天,成了d的一部分,于是平闰年的影响也去掉了,公式就简化成:

D = [ 13 * (M+1) / 5 ] - 7 + (M-1) * 28 + d.(3≤M≤14) (4)

上面计算星期几的公式,也就可以进一步简化成:

W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + [ 13 * (M+1) / 5 ] - 7 + (M-1) *

28 + d.

因为其中的-7和(M-1)*28两项都可以被7整除,所以去掉这两项,W除以7的余数

不变,公式变成:

W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + [ 13 * (M+1) / 5 ] + d. (5) 当然,要注意1月和2月已经被当成了上一年的13月和14月,因此在计算1月和2月的日子的星期时,除了M要按13或14算,年份Y也要减一。比如,2004年1月1日是星

期四,用这个公式来算,有:

W = (2003-1) + [(2003-1)/4] - [(2003-1)/100] + [(2003-1)/400] + [13*(13+1)/5]

+ 1

= 2002 + 500 - 20 + 5 + 36 + 1

= 2524;

2524 / 7 = 360……4.这和实际是一致的。

公式(5)已经是从年、月、日来算星期几的公式了,但它还不是最简练的,对于

年份的处理还有改进的方法。我们先来用这个公式算出每个世纪第一年3月1日的星期,列表如下:

301(701,1101,…,2301)年3月1日的星期数看成是-2(按数论中对余数的定义,-2和5除

以7的余数相同,所以可以做这样的变换),那么这个重复序列正好就是一个4,2,0,-2

的等差数列。据此,我们可以得到下面的计算每个世纪第一年3月1日的星期的公式:W = (4 - C mod 4) * 2 - 4. (6) 式中,C是该世纪的世纪数减一,mod表示取模运算,即求余数。比如,对于2001年3月1日,C=20,则:

W = (4 - 20 mod 4) * 2 - 4

= 8 - 4

= 4.

把公式(6)代入公式(5),经过变换,可得:

(Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] ≡ (4 - C mod 4) * 2 - 1

(mod 7). (7)

因此,公式(5)中的(Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400]这四项,在计算每

个世纪第一年的日期的星期时,可以用(4 - C mod 4) * 2 - 1来代替。这个公式写出来

就是:

W = (4 - C mod 4) * 2 - 1 + [13 * (M+1) / 5] + d. (8) 有了计算每个世纪第一年的日期星期的公式,计算这个世纪其他各年的日期星期的公式就很容易得到了。因为在一个世纪里,末尾为00的年份是最后一年,因此就用

不着再考虑“一百年不闰,四百年又闰”的规则,只须考虑“四年一闰”的规则。仿照由公式(1)简化为公式(2)的方法,我们很容易就可以从式(8)得到一个比公式(5)更简

单的计算任意一天是星期几的公式:

W = (4 - C mod 4) * 2 - 1 + (y-1) + [y/4] + [13 * (M+1) / 5] + d. (9) 式中,y是年份的后两位数字。

如果再考虑到取模运算不是四则运算,我们还可以把(4 - C mod 4) * 2进一步改写成只含四则运算的表达式。因为世纪数减一C除以4的商数q和余数r之间有如下关系:4q + r = C,

其中r即是 C mod 4,因此,有:

r = C - 4q

= C - 4 * [C/4]. (10) 则

(4 - C mod 4) * 2 = (4 - C + 4 * [C/4]) * 2

= 8 - 2C + 8 * [C/4]

≡ [C/4] - 2C + 1 (mod 7). (11) 把式(11)代入(9),得到:

W = [C/4] - 2C + y + [y/4] + [13 * (M+1) / 5] + d - 1. (12) 这个公式由世纪数减一、年份末两位、月份和日数即可算出W,再除以7,得到

的余数是几就表示这一天是星期几,唯一需要变通的是要把1月和2月当成上一年的13月和14月, C和y都按上一年的年份取值。因此,人们普遍认为这是计算任意一天是

星期几的最好的公式。这个公式最早是由德国数学家克里斯蒂安?蔡勒(Christian Zeller, 1822-1899)在1886年推导出的,因此通称为蔡勒公式(Zeller's Formula)。为方便口算,式中的[13 * (M+1) / 5]也往往写成[26 * (M+1) / 10]。

现在仍然让我们来算2004年5月1日的星期,显然C=20,y=4,M=5,d=1,代入

蔡勒公式,有:

W = [20/4] - 40 + 4 + 1 + [13 * (5+1) / 5] + 1 - 1

= -15.

注意负数不能按习惯的余数的概念求余数,只能按数论中的余数的定义求余。为了方便计算,我们可以给它加上一个7的整数倍,使它变为一个正数,比如加上70,

得到55。再除以7,余6,说明这一天是星期六。这和实际是一致的,也和公式(2)计

算所得的结果一致。

最后需要说明的是,上面的公式都是基于公历(格里高利历)的置闰规则来考虑的。对于儒略历,蔡勒也推出了相应的公式是:

W = 5 - C + y + [y/4] + [13 * (M+1) / 5] + d - 1. (13) 这样,我们终于一劳永逸地解决了不查日历计算任何一天是星期几的问题。

第三章方案设计

3.1公历转换农历的基本思想

阳历,有很强的规律性。每年12个月,1、3、5、7、8、10、12月都为31天;2月份平年28天,能被4除尽的年份里为29天,但1900年为28天;其余月份为31天。阴历,却没有这些规律可循。阴历分大小月,大月30天,小月29天,但一年中哪个月为大月,哪个月为小月,却是不定的。阴历每十年有4个润年,但哪一年为润年也是不定的。

而闰月中,哪个闰月为大月,哪个为小月也是不定的。因此,推算阴历就没有一个统一的算法。阴历是要靠天文观测的,因此上面这些不确定的数据,是可以从天文台得到的。

天文台观测的农历月份信息。一年用3个字节表示

| 第23位| 第22-17位 | 第16-13位 | 第12-0位 |

| 保留 | 农历正月初一的年内序数| 闰月 | 一个比特对应一个月份大小|

月份大小数据是月份小的在低位,月份大的在高位,即正月在最低位。以1900年为例,3个字节的数据展开成二进制位:

0 011110 1000 1 0 1 1 0 1 1 0 1 0 0 1 0

保留 1月31日(春节)闰八月从左往右依次十二月,十一月……闰八月、八月、七月……正月的天数,农历月份对应的位为0,表示这个月为29天(小月),为1表示有30天(大月)。

下面就是公历转换成农历的具体算法:

(1)计算所求日期在公历年内的序数DaysNum即该年的多少天。

(2)计算改年农历正月初一在公历年内的序数LunarNewYear,用remain_days表示所求日期距离农历新年的天数,remain_days=DaysNum-LunarNewYear,如果

remain_days<0,则表明所求日期的农历年=公历年-1,根据所求日期距离农历新年的

天数和农历月份的天数信息,从后往前推算出农历日期。如果remain_days>0,表明

所求日期的农历年和公历年相同,根据所求日期距离农历新年的天数以及农历月份的天数信息,从前往后推算出农历日期。

3.2算法流程图

第四章控制台输出日历格式

4.1 算法基本思想

标准的日历格式如下图所示:

可以看出日历中包含的信息有:公历,农历,农历节假日,公历节假日,日期,输出格式的特点有:公历在农历上方显示,当某天正值公里或农历节假日是优先输出假期名称,某天的星期要与日历上星期所在的列对齐。

4.2算法流程图

相关主题