一个日历核心算法的实现

这里是搬家过来的原创文章,本文是09年5月份写的(还没写完:重要的实现算法还没介绍),有点旧了,但总算有个家。于是发到这里。

上周由于工作需要,要做一个带标注的日历查询的JS程序。到网上也搜了不少日历相关的JS代码,但是发现都比较复杂,完全不适合本次开发的需要,于是乎萌生了自己开发一个日历算法的想法。

虽然这个程序的算法难度一般,但是还是冒死放出来溜溜,免得今后忘记了。大家都知道,日历主要是解决星期和日期之间的关系,另外就是一个排版的问题,如何将日期和星期一一对应,这个也是要考虑的重点。那么总结一下要解决的问题:

  1. 给定日期,求出对应星期
  2. 给定日期,求出该月的日历。

一、给定日期,求星期

  • 首先,要知道星期怎么来的,星期从哪天算起,即找到一个计算“原点”,这样之后星期计算就可以有依据了。对于这个问题,其实可以采取反推的办法来实现,找到比如公元元年的星期日(便于求余计算直接得到星期数)的日期。
  • 其次,在知道第一个星期对应的年月日的基础上,求得当前日期是有星期以来多少天,然后用这个间隔天数对一周的天数7取模运算即可求出当前星期几。
  • 因为存在闰年,所以还需要计算有多少个闰年,把这个加上去才能得到间隔天数。

其实这个算法早已存在,下面就这个最常见的公式:

W = [Y-1] + [(Y-1)/4] – [(Y-1)/100] + [(Y-1)/400] + D Y是年份数,D是这一天在这一年中的累积天数,也就是这一天在这一年中是第几天,用个计算机术语就叫相对年初的第0天的偏移量了。

这里就不对这个公式进行推导了,详细推导过程可以到这里下载PDF文档(以下简称PDF):http://download.csdn.net/source/1308663 这个可能要扣一点资源费(莫BS我),表示支持俺的辛苦搜集。

有了上面的公式,接下来就是获得公式里的参数了,其中Y比较容易(地球人人都知道),麻烦的地方在D(其实PDF中Zeller给出了比较简单的算法),不过这里偶比较好奇,所以非要实现D的算法。

为了求D(也就是偏移量),需要计算当前月之前所有月的∑值,以及当前日在当月的偏移量(简称M),那么

D = ∑m + M

其中,∑m 是当年第一月到M所在月前一月的各月天数之和,这个比较简单,关键是确定每个月的天数。原本十二个月每个月天数既定,除了二月份的闰年和平年不一样,这就要根据是否闰年来判断了。根据公里年闰年的算法:则有下面大家所熟知的通用公式。

LeapYear = ( Year / 4   == 0 && Year / 100  !=0) || Year / 400 == 0

下面是给定月份天数算法的C程序实现:

// 给定年月获取当月天数

int getMDay(int y, int m)
{
	int mday[12]=  {31,28,31,30,31,30,31,31,30,31,30,31} ;
	if (( 0 == y % 4 && 0 != y % 100) || 0 == y % 400)
		mday[1] = 29;

	return mday[m-1];
}

有了这个函数,就可以准确得知某日所在月份的天数了。那么计算D就好办了,这样给定日期求星期的算法就完全解决,看代码:

// 获取星期数,0对应星期天 ,1对应星期一,其他类推

int week(int y, int m, int d)
{
	int wk ,date_offset=d,im,tmp=0;
	if (m <= 12 && m >=1 )
	{
		for(im=1; im < m; ++im)
		{
			date_offset += getMDay(y,im);
		}
	}

	/*根据日期计算星期的公式*/
	wk = (y-1 + (y-1)/4 - (y-1)/100  + (y-1)/400  + date_offset)%7;

	return wk;
}

二、给定日期,求出该月的日历

其实上面的都不是本文的重点,本文重点在于如何生成一个日历来,当然方法很多,这里我也给出一个自己的思路,如有雷同,纯属巧合!

由于时间问题,今天就不写了,给下次写留点空间。(看这篇文章的算法实现前传

About 寒江独钓雪

A man's freedom world!
This entry was posted in 算法研究. Bookmark the permalink.

留下评论

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>