参数表所占存储空间为:30 + 4×支持年数
经在MSP430仿真测试,参数表占有154字节,代码占有622字节,执行一次的典型时间是1382个时钟周期。
// -----------------------------------------------------------------
// 农历计算:
// Copy From "西历农历转换程式 黄晓鸣 1995,7,25"
// Modify : Blove
// Date : 16:02 2005-12-1
// -----------------------------------------------------------------
typedef unsigned char INT8U;
typedef unsigned short INT16U;
typedef unsigned long INT32U;
typedef struct _SolarDate_Tag_
{
INT16U wYear;
INT8U chMonth;
INT8U chDate;
}sSolarDateTag;
typedef struct _LunarDate_Tag_
{
INT16U wYear;
INT8U chMonth;
INT8U chDate;
INT8U chKan;
INT8U chChi;
}sLunarDateTag;
// -------------------------------------------------------------------
// 农历计算参数位定义:
// 31-25 7 : ( BaseDays )到公历1月1日到农历正月初一的累积日数
// 24-20 5 : ( Intercalation)闰月月份. 0==此年没有闰月
// 19-13 7 : ( BaseKanChih )此年公历1月1日之干支序号减 1
// 12- 0 13 : ( MonthDays )此农历年每月之大小, 0==小月(29日), 1==大月(30日)
// -------------------------------------------------------------------
#define LPARA_MASK_BASE_DAYS 0xFE000000
#define LPARA_MASK_INTERCALATION 0x01F00000
#define LPARA_MASK_BASE_KANCHI 0x000FE000
#define LPARA_MASK_MONTH_DAYS 0x00001FFF
#define LPARA_SHIFT_BASE_DAYS 25
#define LPARA_SHIFT_INTERCALATION 20
#define LPARA_SHIFT_BASE_KANCHI 13
#define LPARA_SHIFT_MONTH_DAYS 0
#define LPara_GetBaseDays(i) ( (m_dwLunarParas[i]&LPARA_MASK_BASE_DAYS)>>LPARA_SHIFT_BASE_DAYS )
#define LPara_GetIntercalation(i) ( (m_dwLunarParas[i]&LPARA_MASK_INTERCALATION)>>LPARA_SHIFT_INTERCALATION )
#define LPara_GetBaseKanChi(i) ( (m_dwLunarParas[i]&LPARA_MASK_BASE_KANCHI)>>LPARA_SHIFT_BASE_KANCHI )
#define LPara_GetMonthDays(wYear,chMonth) \
( (((m_dwLunarParas[wYear]&LPARA_MASK_MONTH_DAYS)>>LPARA_SHIFT_MONTH_DAYS)>>chMonth)&0x01 )
// -----------------------------------------------------------
// 农历计算参数表
// -----------------------------------------------------------
static const INT32U m_dwLunarParas[] =
{
0x2E47752B, 0x5400952B, 0x3E012A5B, 0x2A21D55A, 0x4E02956A, // 2005
0x38733B55, 0x6003DBA4, 0x4A047B49, 0x32553A93, 0x5805DA95,
0x4206752D, 0x2C470AAD, 0x50004AAD, 0x3C90F5AA, 0x620195D2, // 2015
0x4C022DA5, 0x3662FD4A, 0x5C038D4A, 0x46042C95, 0x3044D52E,
0x54059556, 0x3E062AB5, 0x2A26D5B2, 0x500776D2, 0x3860AEA5, // 2025
0x5E015725, 0x4801F64B, 0x32528C97, 0x56035CAB, 0x4203E55A,
0x2C348AD6 // 2031
};
#define FIRSTYEAR 2001 // 参数表中的第一年
#define YEAR_NUMS ( sizeof(m_dwLunarParas) / sizeof(INT32U) )
#define LASTYEAR ( FIRSTYEAR + YEAR_NUMS - 1 ) // 参数表中的最后一年
// -----------------------------------------------------------
// 公历年每月天数标记表
// 由高位到低位为12-1月:1表示31天,0表示30天,二月除外
// 月份: 12 11 10 9 8 7 6 5 4 3 2 1
// 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 28, 31
// 1 0 1 0 1 1 0 1 0 1 0 1
// -----------------------------------------------------------
static const INT16U m_wSolarMonthDaysFlag = 0x0AD5;
// -----------------------------------------------------------
// 公历年每月累积天数, 平年与闰年
// -----------------------------------------------------------
static const INT16U m_wSolarDays[14] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 396 };
// -----------------------------------------------------------
// 求此公历年是否为闰年, 返回 0 为平年, 1 为闰年
// -----------------------------------------------------------
BOOL Lunar_IsIntercalation( INT16U wYear )
{
if ( wYear % 400 == 0 )
return 1;
else if ( wYear % 100 == 0 )
return 0;
else if ( wYear % 4 == 0 )
return 1;
else
return 0;
}
// -----------------------------------------------------------
// 农历计算
// -----------------------------------------------------------
int Lunar_Cal( sSolarDateTag *psSolarDate, sLunarDateTag *psLunarDate )
{
INT16U wSolarMonth, wDaySum, wSolarDaysSum, im, wTmp1, wTmp2, i, wKanChiSum;
BOOL bLeapFlag;
INT8U chMonthDays, chYearIndex;
// 输入参数的有效性检查
if ( psSolarDate->wYear<=FIRSTYEAR || psSolarDate->wYear>LASTYEAR )
return 1;
wSolarMonth = psSolarDate->chMonth - 1;
if ( wSolarMonth > 11 )
return 2;
bLeapFlag = Lunar_IsIntercalation( psSolarDate->wYear );
if ( wSolarMonth == 1)
// 二月
{
chMonthDays = bLeapFlag + 28;
}
else
// 其他月份
{
chMonthDays = 30 + ((m_wSolarMonthDaysFlag>>wSolarMonth)&0x01);
}
if ( psSolarDate->chDate<1 || psSolarDate->chDate>chMonthDays )
return 3;
chYearIndex = psSolarDate->wYear - FIRSTYEAR;
wSolarDaysSum = m_wSolarDays[wSolarMonth];
if ( wSolarMonth > 1 )
wSolarDaysSum += bLeapFlag;
wDaySum = wSolarDaysSum + psSolarDate->chDate;
wKanChiSum = wDaySum + LPara_GetBaseKanChi(chYearIndex);
psLunarDate->chKan = wKanChiSum % 10;
psLunarDate->chChi = wKanChiSum % 12;
if ( wDaySum <= LPara_GetBaseDays(chYearIndex) )
{
chYearIndex--;
psLunarDate->wYear = psSolarDate->wYear - 1;
bLeapFlag = Lunar_IsIntercalation( psLunarDate->wYear );
wSolarMonth += 12;
wSolarDaysSum = m_wSolarDays[wSolarMonth];
if ( wSolarMonth > 1 )
wSolarDaysSum += bLeapFlag;
wDaySum = wSolarDaysSum + psSolarDate->chDate;
}
else
{
psLunarDate->wYear = psSolarDate->wYear;
}
wTmp1 = LPara_GetBaseDays(chYearIndex);
for ( i=0; i<13; i++ )
{
wTmp2 = wTmp1 + LPara_GetMonthDays( chYearIndex, i) + 29;
if ( wDaySum <= wTmp2 )
break;
wTmp1 = wTmp2;
}
psLunarDate->chMonth = i + 1;
psLunarDate->chDate = wDaySum - wTmp1;
im = LPara_GetIntercalation(chYearIndex);
if ( im != 0 && psLunarDate->chMonth > im)
psLunarDate->chMonth--;
if ( psLunarDate->chMonth > 12)
psLunarDate->chMonth -= 12;
return 0;
}