抱雪
你到过我的主页吗?在我的主页上有这样一个地方:
你注意到了吗,在显示时间的地方除了显示公历之外,还显示了农历:农历辛已(蛇)年二月廿三日未时,比一般的网站上只显示公历就酷多了(怎么像自吹自擂?别的网站千万别去告我违反了广告法)。这是怎么做的呢?其实很简单,只要一个小小的PHP或者JavaScript
程序就可以了。
你不要着急地问我要PHP或JS的程序,最关键的是要了解算法,如果你明白了转换的道理,就可以达到圣人所说的:举一而三反焉,到时不管是用PHP、DELPHI、JS还是
JSP、VB,你都可以很快地写公历农历相互转换的
程序来出来。我记得有高人曾经说过,编程语言只是工具,数据结构才是最重要的,此言诚不虚也。
闲话少说,下面我就来介绍一下具体的算法。
首先是要保存公农历之间的转换信息:以任意一年作为起点,把从这一年起若干年(若干是多少?就看你的需要了)的农历信息保存起来(在我的VCL中,是以1921年作为起点)。回想一下,我们平常是怎样来转换公历农历的呢?是查万年历,万年历有每一天的公历农历,直接一查就可以了。那么我们可不可以也这样做呢?当然可以,但是,这样做就要收录每一天的信息,工作量就会很大,所以我们要简化这些信息。怎么简化呢?要保存一年的信息其实只要两个信息就可以了:1、农历每个月的大小;2、今年是否有闰月,闰几月以及闰月的大小。用一个整数来保存这些信息就足够了。具体的方法是:用一位来表示一个月的大小,大月记为1,小月记为0,这样就用掉12位(无闰月)或13位(有闰月),再用高4位来表示闰月的月份,没有闰月记为0。比如说,2000年的信息数据是是0xC96,化成二进制就是110010010110B,表示的含义是指1、2、5、8、10、11月大,其余月小;2001年的农历信息数据是0x41A95,其中4表示今年闰四月,月份大小信息就是0x1A95(因为闰月,所以有13位),具体的就是1、2、4、5、8、10、12月大,其余月份小(0x1A95=1101010010101B),要注意在四月的后面那一个0表示的是闰四月小,接着的那个1表示5月大。这样就可以用一个数组来保存这些信息。在我的VCL
程序中是用ChineseCalendarData这个数组来保存这些信息。
为了方便对算法的理解,首先来看看我的VCL组件hsDivineCalendar的头文件
//---------------------------------------------------------------------------
#ifndef hsDivineCalendarH
#define hsDivineCalendarH
#define ALLYEARS 100 //定义转换的年数:100年
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE ThsDivineCalendar : public TComponent
{
private:
int ChineseCalendarData[ALLYEARS]; //农历数据
AnsiString str2,num; //要用的字符串
void __fastcall c2e(); //农历到公历
void __fastcall e2c(); //公历到农历