Friday, November 11, 2005

 

Some notes on Chinese Lunar Years

I.
首先还是来个恐怖的查表法

计算农历的一个类

By wangfei@hanwang.com.cn
From http://www.moon-soft.com/program/doc/readelite9948.htm

“ 致看到这些源代码的兄弟:
你好!
这本来是我为一个商业PDA产品开发的日历程序,最近移植于PC机上, 所以算法和数据部分是用纯C++写的,不涉及MFC,所有的代码都是以短节省存储空间为主要目的.很高兴你对这些代码有兴趣,你可以随意复制和使用些代码,唯一有一点小小的愿望:在你使用和复制给别人时,别忘注明这些代码作者:-)。程序代码也就罢了,后面的数据可是我辛辛苦苦从万年历上找出来输进去的。如果你有什么好的意见不妨Mail给我。

wangfei@hanwang.com.cn 或 wangfei@engineer.com.cn 2000年”

.h file

#if !defined(AFX_CALENDAR1_H__FD9A6DAF_8C3C_493C_AAD4_612134D8F6D4__IN

CLUDED_)
#define AFX_CALENDAR1_H__FD9A6DAF_8C3C_493C_AAD4_612134D8F6D4__INCLUDE

D_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// Calendar1.h : header file
//////////////////////////////////////////////////////////////////////

///////
// CCalendar window
extern const WORD START_YEAR;
extern const WORD END_YEAR;

//define user message select changed
#define UM_SELCHANGE (WM_USER+101)

class CCalendar : public CWnd
{
private:
WORD m_iYear, m_iMonth, m_iDay;
CBitmap m_oBitMapList[42];
CMenu m_oPopMenu;

public:
COLORREF m_dwBackColor, m_dwForeColor;
COLORREF m_dwSelColor, m_dwSelForeColor;
COLORREF m_dwTitleBkColor, m_dwTitleColor;

public:
CCalendar(WORD iYear, WORD iMonth, WORD iDay);
CCalendar();
virtual BOOL Create(RECT &rect, CWnd * pParentWnd, UINT nID);

public:
WORD GetYear(){return m_iYear;}
WORD GetMonth(){return m_iMonth;}
WORD GetDay(){return m_iDay;}
void GetDate(WORD &iYear, WORD &iMonth, WORD &iDay);
BOOL SetDate(WORD iYear, WORD iMonth, WORD iDay);

protected:
CButton m_obutToday;
//{{AFX_MSG(CCalendar)
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
//}}AFX_MSG
afx_msg void OnTitleBkColor();
afx_msg void OnTitleColor();
afx_msg void OnSelColor();
afx_msg void OnForeColor();
DECLARE_MESSAGE_MAP()


public:
//判断iYear是不是闰年
static BOOL IsLeapYear(WORD iYear)
{return !(iYear%4)&&(iYear%100) || !(iYear%400);}

//计算iYear,iMonth,iDay对应是星期几 1年1月1日 --- 65535年12月31日
static WORD WeekDay(WORD iYear, WORD iMonth, WORD iDay);

//返回iYear年iMonth月的天数 1年1月 --- 65535年12月
static WORD MonthDays(WORD iYear, WORD iMonth);

//返回阴历iLunarYer年阴历iLunarMonth月的天数,如果iLunarMonth为闰月,


//高字为第二个iLunarMonth月的天数,否则高字为0
// 1901年1月---2050年12月
static LONG LunarMonthDays(WORD iLunarYear, WORD iLunarMonth);

//返回阴历iLunarYear年的总天数
// 1901年1月---2050年12月
static WORD LunarYearDays(WORD iLunarYear);

//返回阴历iLunarYear年的闰月月份,如没有返回0
// 1901年1月---2050年12月
static WORD GetLeapMonth(WORD iLunarYear);

//把iYear年格式化成天干记年法表示的字符串
static void FormatLunarYear(WORD iYear, char *pBuffer);

//把iMonth格式化成中文字符串
static void FormatMonth(WORD iMonth, char *pBuffer, BOOL bLunar = TRU

E);

//把iDay格式化成中文字符串
static void FormatLunarDay(WORD iDay, char *pBuffer);

//计算公历两个日期间相差的天数 1年1月1日 --- 65535年12月31日
static LONG CalcDateDiff(WORD iEndYear, WORD iEndMonth, WORD iEndDay,


WORD iStartYear = START_YEAR,
WORD iStartMonth =1, WORD iStartDay =1);

//计算公历iYear年iMonth月iDay日对应的阴历日期,返回对应的阴历节气 0-24


//1901年1月1日---2050年12月31日
static WORD GetLunarDate(WORD iYear, WORD iMonth, WORD iDay,
WORD &iLunarYear, WORD &iLunarMonth, WORD &iLun

arDay);

public:
virtual ~CCalendar();

private:
void l_InitData();

//计算从1901年1月1日过iSpanDays天后的阴历日期
static void l_CalcLunarDate(WORD &iYear, WORD &iMonth ,WORD &iDay,

LONG iSpanDays);
//计算公历iYear年iMonth月iDay日对应的节气 0-24,0表不是节气
static WORD l_GetLunarHolDay(WORD iYear, WORD iMonth, WORD iDay);

WORD l_CalcSelectDay(POINT * pt);
void l_PaintTitle(CPaintDC &dc);
void l_PaintDate(CPaintDC &dc);
inline void l_PaintOneDay(CPaintDC &dc, CDC &imgdc, WORD &iDay,
WORD &iLunarYear,
WORD &iLunarMonth, WORD &iLuanrDay,
LONG startx, LONG starty);
};

//////////////////////////////////////////////////////////////////////

///////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediatel

y before the previous line.

#endif // !defined(AFX_CALENDAR1_H__FD9A6DAF_8C3C_493C_AAD4_612134D8F6

D4__INCLUDED_)

.cpp file

#include "stdafx.h"
#include "Calendar.h"
#include "Calendar1.h"
#include "Calendarfrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////

///////
// CCalendar


extern WORD gLunarMonthDay[];
extern BYTE gLunarMonth[];
extern BYTE gLunarHolDay[];

const WORD START_YEAR =1901;
const WORD END_YEAR =2050;

void CCalendar::l_InitData()
{
SYSTEMTIME systime;
::GetSystemTime(&systime);

m_iYear = systime.wYear;
m_iMonth = systime.wMonth;
m_iDay = systime.wDay;

m_dwBackColor = RGB(255,255,255);
m_dwForeColor = RGB(0,0,0);
m_dwSelColor = RGB(150,150,230);
m_dwSelForeColor = RGB(255,255,255);
m_dwTitleBkColor = RGB(190,70,70);
m_dwTitleColor = RGB(255,255,0);

}

CCalendar::CCalendar(WORD iYear, WORD iMonth, WORD iDay)
{
if(!SetDate(iYear, iMonth, iDay))
l_InitData();
}

CCalendar::CCalendar()
{
l_InitData();
}

CCalendar::~CCalendar()
{
DestroyWindow();
}


BEGIN_MESSAGE_MAP(CCalendar, CWnd)
//{{AFX_MSG_MAP(CCalendar)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_CONTEXTMENU()
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND(ID_TITLEBKCOLOR, OnTitleBkColor)
ON_COMMAND(ID_TITLECOLOR, OnTitleColor)
ON_COMMAND(ID_SELCOLOR, OnSelColor)
ON_COMMAND(ID_FORECOLOR, OnForeColor)
END_MESSAGE_MAP()

#define COL_WIDTH 32
#define ROW_HEIGHT 20
#define TITLE_HEIGHT 20

BOOL CCalendar::Create(RECT &rect, CWnd *pParentWnd, UINT nID)
{
CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|


CS_HREDRAW|CS_VREDRAW,
0, (HBRUSH)CBrush(RGB(25

5,255,255)), 0);

rect.right = rect.left + COL_WIDTH*7 +4;
rect.bottom = rect.top + TITLE_HEIGHT+ROW_HEIGHT*6 +10 ;
if(!CWnd::CreateEx(WS_EX_CLIENTEDGE, szClassName, _T(""),
WS_CHILD|WS_VISIBLE|WS_TABSTOP, rect,
pParentWnd, nID, NULL))

return FALSE;

UpdateWindow();
for(int i=0; i<42; i++)
m_oBitMapList[i].LoadBitmap(IDB_BITMAP1+i);

m_oPopMenu.CreatePopupMenu();
m_oPopMenu.AppendMenu(MF_STRING, ID_TITLEBKCOLOR, _T("标题背景色...")

);
m_oPopMenu.AppendMenu(MF_STRING, ID_TITLECOLOR, _T("标题前景色...")

);
m_oPopMenu.AppendMenu(MF_STRING, ID_FORECOLOR , _T("日期前景色...")

);
m_oPopMenu.AppendMenu(MF_STRING, ID_SELCOLOR, _T("选中区颜色..."

));

return TRUE;
}

//////////////////////////////////////////////////////////////////////

///////
// CCalendar message handlers
void CCalendar::l_PaintTitle(CPaintDC &dc)
{
CRect rect ;
GetClientRect(&rect);

rect.left ++; rect.top ++;
rect.right --; rect.bottom = rect.top + TITLE_HEIGHT;
dc.FillRect(&rect, &CBrush(m_dwTitleBkColor));

dc.SetBkColor(m_dwTitleBkColor);
dc.SetTextColor(m_dwTitleColor);

int startx = rect.left +8;
char sztext[][3]={"日","一","二","三","四","五","六"};
for(int i=0; i <7; i++)
{
dc.TextOut(startx, rect.top +2, sztext[i]);
startx += COL_WIDTH;
}
}

void CCalendar:: l_PaintOneDay(CPaintDC &dc, CDC &imgdc, WORD &iDay,


WORD &iLunarYear, WORD &iLunarMonth,
WORD &iLunarDay,
LONG startx, LONG starty)
{
char text[3];
sprintf(text, "%2d", iDay);

// select icon
if(iLunarDay!=1)
imgdc.SelectObject(&m_oBitMapList[iLunarDay-1]);
else
imgdc.SelectObject(&m_oBitMapList[29+iLunarMonth]);

// if day == current day
if(iDay++ == m_iDay)
{
dc.FillRect(&CRect(startx-1, starty,
startx +COL_WIDTH-3, starty + ROW_HEIGHT),
&CBrush(m_dwSelColor));
dc.SetTextColor(m_dwSelForeColor);
dc.SetBkColor(m_dwSelColor);
dc.TextOut(startx, starty +2, text);
dc.SetBkColor(m_dwBackColor);
dc.SetTextColor(m_dwForeColor);
dc.BitBlt(startx+17, starty +2, 8,16,&imgdc,0,0,MERGEPAINT);
}
else
{
dc.TextOut(startx, starty+2, text);
dc.BitBlt(startx+17, starty +2, 8,16,&imgdc,0,0,SRCCOPY);
}

if(iLunarDay<29)
iLunarDay++;
else
{
LONG days = LunarMonthDays(iLunarYear, iLunarMonth);
if(!HIWORD(days) && iLunarDay == LOWORD(days))
iLunarMonth = (iLunarMonth)%12+1;
if(iLunarDay < LOBYTE(days))
iLunarDay++;
else
iLunarDay =1;
}
}

void CCalendar::l_PaintDate(CPaintDC &dc)
{
CDC imgdc;
imgdc.CreateCompatibleDC(&dc);

RECT rect;
GetClientRect(&rect);
rect.top +=TITLE_HEIGHT+6;

dc.SetBkColor(m_dwBackColor);
dc.SetTextColor(m_dwForeColor);

WORD day =1;
WORD iLunarYear, iLunarMonth, iLunarDay;
GetLunarDate(m_iYear, m_iMonth, 1, iLunarYear, iLunarMonth, iLunarD

ay);

for(int i=0; i<6; i++, rect.top += ROW_HEIGHT)
{
long startx = rect.left +2;
for(int j=0; j<7; j++,startx += COL_WIDTH)
{
if(j < WeekDay(m_iYear, m_iMonth, 1) && i==0)
continue;

if(day > MonthDays(m_iYear, m_iMonth))
break;

l_PaintOneDay(dc, imgdc, day, iLunarYear, iLunarMonth,
iLunarDay, startx, rect.top);
}
}
}

void CCalendar::OnPaint()
{
CPaintDC dc(this); // device context for painting

CFont *font = ((CCalendarFrm *)GetParent())->GetDispFont();
dc.SelectObject(font);
dc.SetMapMode(0);
l_PaintTitle(dc);
l_PaintDate(dc);

}

LONG CCalendar::CalcDateDiff(WORD iEndYear, WORD iEndMonth, WORD iEndD

ay,
WORD iStartYear, WORD iStartMonth, WORD iStartD

ay)
{
WORD monthday[]={0, 31, 59 ,90, 120, 151, 181, 212, 243, 273, 304, 33

4};

//计算两个年份1月1日之间相差的天数
LONG iDiffDays =(iEndYear - iStartYear)*365;
iDiffDays += (iEndYear-1)/4 - (iStartYear-1)/4;
iDiffDays -= ((iEndYear-1)/100 - (iStartYear-1)/100);
iDiffDays += (iEndYear-1)/400 - (iStartYear-1)/400;

//加上iEndYear年1月1日到iEndMonth月iEndDay日之间的天数
iDiffDays += monthday[iEndMonth-1] +
(IsLeapYear(iEndYear)&&iEndMonth>2? 1: 0)

;
iDiffDays += iEndDay;

//减去iStartYear年1月1日到iStartMonth月iStartDay日之间的天数
iDiffDays -= (monthday[iStartMonth-1] +
(IsLeapYear(iStartYear)&&iStartMonth>2 ? 1: 0));
iDiffDays -= iStartDay;
return iDiffDays;
}

void CCalendar::l_CalcLunarDate(WORD &iYear, WORD &iMonth ,WORD &iDay

, LONG iSpanDays)
{
//阳历1901年2月19日为阴历1901年正月初一
//阳历1901年1月1日到2月19日共有49天
if(iSpanDays <49)
{
iYear = START_YEAR-1;
if(iSpanDays <19)
{
iMonth = 11;
iDay = 11+WORD(iSpanDays);
}
else
{
iMonth = 12;
iDay = WORD(iSpanDays) -18;
}
return ;
}
//下面从阴历1901年正月初一算起
iSpanDays -=49;
iYear = START_YEAR;
iMonth = 1;
iDay = 1;
//计算年
LONG tmp = LunarYearDays(iYear);
while(iSpanDays >= tmp)
{
iSpanDays -= tmp;
tmp = LunarYearDays(++iYear);
}
//计算月
tmp = LOWORD(LunarMonthDays(iYear, iMonth));
while(iSpanDays >= tmp)
{
iSpanDays -= tmp;
if(iMonth == GetLeapMonth(iYear))
{
tmp = HIWORD(LunarMonthDays(iYear, iMonth));
if(iSpanDays < tmp)
break;
iSpanDays -= tmp;
}
tmp = LOWORD(LunarMonthDays(iYear, ++iMonth));
}
//计算日
iDay += WORD(iSpanDays);
}

WORD CCalendar::GetLunarDate(WORD iYear, WORD iMonth, WORD iDay,
WORD &iLunarYear, WORD &iLunarMonth, WORD &iLun

arDay)
{
l_CalcLunarDate(iLunarYear, iLunarMonth, iLunarDay,
CalcDateDiff(iYear, iMonth, iDay));

return l_GetLunarHolDay(iYear, iMonth, iDay);
}

//根据节气数据存储格式,计算阳历iYear年iMonth月iDay日对应的节气,
WORD CCalendar::l_GetLunarHolDay(WORD iYear, WORD iMonth, WORD iDay)


{
BYTE &flag = gLunarHolDay[(iYear - START_YEAR)*12+iMonth -1];
WORD day;
if(iDay <15)
day= 15 - ((flag>>4)&0x0f);
else
day = ((flag)&0x0f)+15;
if(iDay == day)
return (iMonth-1) *2 + (iDay>15? 1: 0) +1;
else
return 0;
}

void CCalendar::GetDate(WORD &iYear, WORD &iMonth, WORD &iDay)
{
iYear = m_iYear;
iMonth = m_iMonth;
iDay = m_iDay;
}

BOOL CCalendar::SetDate(WORD iYear, WORD iMonth, WORD iDay)
{
if(iYear < START_YEAR || iYear > END_YEAR || iMonth <1 || iMonth >12

)
return FALSE;

if(iDay <1 || iDay > MonthDays(iYear, iMonth))
return FALSE;

m_iYear = iYear;
m_iMonth = iMonth;
m_iDay = iDay;

return TRUE;
}

WORD CCalendar::WeekDay(WORD iYear, WORD iMonth, WORD iDay)
{
//数组元素monthday[i]表示第i个月以前的总天数除以7的余数
WORD monthday[]={0,3,3,6,1,4,6,2,5,0,3,5};
WORD iDays = (iYear-1)%7 + (iYear-1)/4 - (iYear-1)/100 +(iYear-1)/400

;
iDays += (monthday[iMonth-1] +iDay) ;
//如果iYear是闰年
if(IsLeapYear(iYear) && iMonth>2)
iDays++;
//返回:0,1,2,3,4,5,6表日、一、二、三、四、五、六
return iDays%7;
}

WORD CCalendar::MonthDays(WORD iYear, WORD iMonth)
{
switch(iMonth)
{
case 1:case 3:case 5:case 7:case 8:case 10:case 12:
return 31;
break;
case 4:case 6:case 9:case 11:
return 30;
break;
case 2:
//如果是闰年
if(IsLeapYear(iYear))
return 29;
else
return 28;
break;
}
return 0;
}

WORD CCalendar::GetLeapMonth(WORD iLunarYear)
{
BYTE &flag = gLunarMonth[(iLunarYear - START_YEAR)/2];
return (iLunarYear - START_YEAR)%2 ? flag&0x0f : flag>>4;
}

LONG CCalendar::LunarMonthDays(WORD iLunarYear, WORD iLunarMonth)
{
if(iLunarYear < START_YEAR)
return 30L;

WORD height =0 ,low =29;
int iBit = 16 - iLunarMonth;

if(iLunarMonth > GetLeapMonth(iLunarYear) && GetLeapMonth(iLunarYe

ar))
iBit --;

if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<low ++;

if(iLunarMonth == GetLeapMonth(iLunarYear))
if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<< (iBit -1)))
height =30;
else
height =29;

return MAKELONG(low, height);
}

WORD CCalendar::LunarYearDays(WORD iLunarYear)
{
/*
WORD days=348 ; //12*29
int month = 12 ;
//如果iYear年有闰月,则为13个月
if(gLanarMonth[iYear - START_YEAR])
month ++;
//如果某月是三十天则days++
while(month >=0 && (gLanarMonthDay[iYear - START_YEAR] & (1 << (16 -

month))))
{
days ++;
month --;
}
return days;
*/
WORD days =0;
for(WORD i=1; i<=12; i++)
{
LONG tmp = LunarMonthDays(iLunarYear ,i);
days += HIWORD(tmp);
days += LOWORD(tmp);
}
return days;
}

void CCalendar::FormatLunarYear(WORD iYear, char *pBuffer)
{
char szText1[]="甲乙丙丁戊己庚辛壬癸";
char szText2[]="子丑寅卯辰巳午未申酉戌亥";
char szText3[]="鼠牛虎免龙蛇马羊猴鸡狗猪";

memcpy(pBuffer, szText1+((iYear-4)%10)*2,2);
memcpy(pBuffer+2,szText2+((iYear-4)%12)*2,2);
pBuffer[4]=' ';
memcpy(pBuffer+5,szText3+((iYear-4)%12)*2,2);
strcpy(pBuffer+7,"年");
}

void CCalendar::FormatMonth(WORD iMonth, char *pBuffer, BOOL bLunar)

{
if(!bLunar && iMonth==1)
{
strcpy(pBuffer, " 一月");
return;
}

char szText[]="正二三四五六七八九十";
if(iMonth<=10)
{
memcpy(pBuffer, " ", 2);
memcpy(pBuffer+2, szText + (iMonth -1)*2, 2);
strcpy(pBuffer+4 , "月");
return;
}
if (iMonth == 11)
strcpy(pBuffer, "十一");
else
strcpy(pBuffer, "十二");
strcpy(pBuffer+4 , "月");


}
void CCalendar::FormatLunarDay(WORD iDay, char *pBuffer)
{
char szText1[]="初十廿三";
char szText2[]="一二三四五六七八九十";
if(iDay != 20 && iDay !=30)
{
memcpy(pBuffer, szText1 + (iDay-1)/10*2 ,2);
memcpy(pBuffer+2, szText2 + ((iDay-1)%10)*2 ,2);
pBuffer[4]='\0';
}
else
{
memcpy(pBuffer, szText1 + iDay/10*2, 2);
strcpy(pBuffer+2, szText2 +18);
}
}
WORD CCalendar::l_CalcSelectDay(POINT * pt)
{
RECT rect;
GetClientRect(&rect);
WORD iRow = (pt->y - rect.top -26)/ROW_HEIGHT;
WORD iCol = (pt->x - rect.left )/COL_WIDTH;

WORD startcol ,endrow, endcol;
startcol = WeekDay(m_iYear, m_iMonth, 1);
endcol = WeekDay(m_iYear, m_iMonth, MonthDays(m_iYear,m_iMonth));

endrow = (MonthDays(m_iYear, m_iMonth) + startcol -1)/7 ;
if(iRow == 0 && iCol < startcol || iRow == endrow && iCol > endcol

|| iRow > endrow)
return 0;
return iRow *7 + iCol + 1 - startcol ;
}

void CCalendar::OnLButtonDown(UINT nFlags, CPoint point)
{
WORD day = l_CalcSelectDay(&point);
if(day !=0 && day != m_iDay)
{
m_iDay = day;
::PostMessage(GetParent()->m_hWnd, UM_SELCHANGE, MAKELONG(m_iMonth,
m_iYear), m_iDay);
}
SetFocus();
CWnd::OnLButtonDown(nFlags, point);
}


void CCalendar::OnContextMenu(CWnd* pWnd, CPoint point)
{
m_oPopMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, p

oint.y,
this);
}

void CCalendar::OnTitleBkColor()
{
CColorDialog colordlg;
if(colordlg.DoModal() != IDOK)
return;
m_dwTitleBkColor = colordlg.GetColor();
Invalidate();
}

void CCalendar::OnTitleColor()
{
CColorDialog colordlg;
if(colordlg.DoModal() != IDOK)
return;
m_dwTitleColor = colordlg.GetColor();
Invalidate();
}

void CCalendar::OnSelColor()
{
CColorDialog colordlg;
if(colordlg.DoModal() != IDOK)
return;

m_dwSelColor = colordlg.GetColor();
Invalidate();
}

void CCalendar::OnForeColor()
{
CColorDialog colordlg;
if(colordlg.DoModal() != IDOK)
return;

m_dwForeColor = colordlg.GetColor();
Invalidate();
}

#undef COL_WIDTH
#undef ROW_HEIGHT
#undef TITLE_HEIGHT
/*********************************************************************

*********
下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方

法.

**********************************************************************

*********/
//数组gLunarDay存入阴历1901年到2100年每年中的月天数信息,
//阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表3

0天,否则为29天
WORD gLunarMonthDay[]=
{
//测试数据只有1901.1.1 --2050.12.31
0X4ae0, 0Xa570, 0X5268, 0Xd260, 0Xd950, 0X6aa8, 0X56a0, 0X9ad0, 0X4a

e8, 0X4ae0, //1910
0Xa4d8, 0Xa4d0, 0Xd250, 0Xd548, 0Xb550, 0X56a0, 0X96d0, 0X95b0, 0X49

b8, 0X49b0, //1920
0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada8, 0X2b60, 0X9570, 0X4978, 0X49

70, 0X64b0, //1930
0Xd4a0, 0Xea50, 0X6d48, 0X5ad0, 0X2b60, 0X9370, 0X92e0, 0Xc968, 0Xc9

50, 0Xd4a0, //1940
0Xda50, 0Xb550, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc958, 0Xa950, 0Xb4

a8, 0X6ca0, //1950
0Xb550, 0X55a8, 0X4da0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa950, 0Xe950, 0X6a

a0, 0Xad50, //1960
0Xab50, 0X4b60, 0Xa570, 0Xa570, 0X5260, 0Xe930, 0Xd950, 0X5aa8, 0X56

a0, 0X96d0, //1970
0X4ae8, 0X4ad0, 0Xa4d0, 0Xd268, 0Xd250, 0Xd528, 0Xb540, 0Xb6a0, 0X96

d0, 0X95b0, //1980
0X49b0, 0Xa4b8, 0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada0, 0Xab60, 0X93

70, 0X4978, //1990
0X4970, 0X64b0, 0X6a50, 0Xea50, 0X6b28, 0X5ac0, 0Xab60, 0X9368, 0X92

e0, 0Xc960, //2000
0Xd4a8, 0Xd4a0, 0Xda50, 0X5aa8, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc9

58, 0Xa950, //2010
0Xb4a0, 0Xb550, 0Xb550, 0X55a8, 0X4ba0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa9

30, 0X74a8, //2020
0X6aa0, 0Xad50, 0X4da8, 0X4b60, 0X9570, 0Xa4e0, 0Xd260, 0Xe930, 0Xd5

30, 0X5aa0, //2030
0X6b50, 0X96d0, 0X4ae8, 0X4ad0, 0Xa4d0, 0Xd258, 0Xd250, 0Xd520, 0Xda

a0, 0Xb5a0, //2040
0X56d0, 0X4ad8, 0X49b0, 0Xa4b8, 0Xa4b0, 0Xaa50, 0Xb528, 0X6d20, 0Xad

a0, 0X55b0, //2050

};

//数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节

存两年
BYTE gLunarMonth[]=
{
0X00, 0X50, 0X04, 0X00, 0X20, //1910
0X60, 0X05, 0X00, 0X20, 0X70, //1920
0X05, 0X00, 0X40, 0X02, 0X06, //1930
0X00, 0X50, 0X03, 0X07, 0X00, //1940
0X60, 0X04, 0X00, 0X20, 0X70, //1950
0X05, 0X00, 0X30, 0X80, 0X06, //1960
0X00, 0X40, 0X03, 0X07, 0X00, //1970
0X50, 0X04, 0X08, 0X00, 0X60, //1980
0X04, 0X0a, 0X00, 0X60, 0X05, //1990
0X00, 0X30, 0X80, 0X05, 0X00, //2000
0X40, 0X02, 0X07, 0X00, 0X50, //2010
0X04, 0X09, 0X00, 0X60, 0X04, //2020
0X00, 0X20, 0X60, 0X05, 0X00, //2030
0X30, 0Xb0, 0X06, 0X00, 0X50, //2040
0X02, 0X07, 0X00, 0X50, 0X03 //2050
};

//数组gLanarHoliDay存放每年的二十四节气对应的阳历日期
//每年的二十四节气对应的阳历日期几乎固定,平均分布于十二个月中
// 1月 2月 3月 4月 5月 6月


//小寒 大寒 立春 雨水 惊蛰 春分 清明 谷雨 立夏 小满 芒种 夏


// 7月 8月 9月 10月 11月 12月


//小暑 大暑 立秋 处暑 白露 秋分 寒露 霜降 立冬 小雪 大雪 冬



/*********************************************************************

************
节气无任何确定规律,所以只好存表,要节省空间,所以....
下面这种存法实在是太变态了,你就将就着看吧
**********************************************************************

************/
//数据格式说明:
//如1901年的节气为
// 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月

11月 12月
// 6, 21, 4, 19, 6, 21, 5, 21, 6,22, 6,22, 8, 23, 8, 24, 8, 24, 8, 24

, 8, 23, 8, 22
// 9, 6, 11,4, 9, 6, 10,6, 9,7, 9,7, 7, 8, 7, 9, 7, 9, 7, 9

, 7, 8, 7, 15
//上面第一行数据为每月节气对应日期,15减去每月第一个节气,每月第二个节气

减去15得第二行
// 这样每月两个节气对应数据都小于16,每月用一个字节存放,高位存放第一个节

气数据,低位存放
//第二个节气的数据,可得下表

BYTE gLunarHolDay[]=
{
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1901
0X96, 0XA4, 0X96, 0X96, 0X97, 0X87, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1902
0X96, 0XA5, 0X87, 0X96, 0X87, 0X87, 0X79, 0X69, 0X69, 0X69, 0X78, 0X7

8, //1903
0X86, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X78, 0X8

7, //1904
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1905
0X96, 0XA4, 0X96, 0X96, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1906
0X96, 0XA5, 0X87, 0X96, 0X87, 0X87, 0X79, 0X69, 0X69, 0X69, 0X78, 0X7

8, //1907
0X86, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1908
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1909
0X96, 0XA4, 0X96, 0X96, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1910
0X96, 0XA5, 0X87, 0X96, 0X87, 0X87, 0X79, 0X69, 0X69, 0X69, 0X78, 0X7

8, //1911
0X86, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1912
0X95, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1913
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1914
0X96, 0XA5, 0X97, 0X96, 0X97, 0X87, 0X79, 0X79, 0X69, 0X69, 0X78, 0X7

8, //1915
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1916
0X95, 0XB4, 0X96, 0XA6, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X8

7, //1917
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1918
0X96, 0XA5, 0X97, 0X96, 0X97, 0X87, 0X79, 0X79, 0X69, 0X69, 0X78, 0X7

8, //1919
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1920
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X8

7, //1921
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1922
0X96, 0XA4, 0X96, 0X96, 0X97, 0X87, 0X79, 0X79, 0X69, 0X69, 0X78, 0X7

8, //1923
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1924
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X8

7, //1925
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1926
0X96, 0XA4, 0X96, 0X96, 0X97, 0X87, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1927
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1928
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1929
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1930
0X96, 0XA4, 0X96, 0X96, 0X97, 0X87, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1931
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1932
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1933
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1934
0X96, 0XA4, 0X96, 0X96, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1935
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1936
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1937
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1938
0X96, 0XA4, 0X96, 0X96, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1939
0X96, 0XA5, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1940
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1941
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1942
0X96, 0XA4, 0X96, 0X96, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1943
0X96, 0XA5, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1944
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1945
0X95, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X7

7, //1946
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1947
0X96, 0XA5, 0XA6, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //1948
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X79, 0X78, 0X79, 0X77, 0X8

7, //1949
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X7

7, //1950
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X79, 0X79, 0X79, 0X69, 0X78, 0X7

8, //1951
0X96, 0XA5, 0XA6, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //1952
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1953
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X78, 0X79, 0X78, 0X68, 0X78, 0X8

7, //1954
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1955
0X96, 0XA5, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //1956
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1957
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1958
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1959
0X96, 0XA4, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1960
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1961
0X96, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1962
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1963
0X96, 0XA4, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1964
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1965
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1966
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1967
0X96, 0XA4, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1968
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1969
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1970
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X79, 0X69, 0X78, 0X7

7, //1971
0X96, 0XA4, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1972
0XA5, 0XB5, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1973
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1974
0X96, 0XB4, 0X96, 0XA6, 0X97, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X7

7, //1975
0X96, 0XA4, 0XA5, 0XB5, 0XA6, 0XA6, 0X88, 0X89, 0X88, 0X78, 0X87, 0X8

7, //1976
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //1977
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X78, 0X8

7, //1978
0X96, 0XB4, 0X96, 0XA6, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X7

7, //1979
0X96, 0XA4, 0XA5, 0XB5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1980
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X77, 0X8

7, //1981
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1982
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X78, 0X79, 0X78, 0X69, 0X78, 0X7

7, //1983
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1984
0XA5, 0XB4, 0XA6, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //1985
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1986
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X79, 0X78, 0X69, 0X78, 0X8

7, //1987
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //1988
0XA5, 0XB4, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1989
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //1990
0X95, 0XB4, 0X96, 0XA5, 0X86, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1991
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //1992
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1993
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1994
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X76, 0X78, 0X69, 0X78, 0X8

7, //1995
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //1996
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //1997
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //1998
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //1999
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2000
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2001
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //2002
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //2003
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2004
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2005
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2006
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X69, 0X78, 0X8

7, //2007
0X96, 0XB4, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X87, 0X78, 0X87, 0X8

6, //2008
0XA5, 0XB3, 0XA5, 0XB5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2009
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2010
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X78, 0X8

7, //2011
0X96, 0XB4, 0XA5, 0XB5, 0XA5, 0XA6, 0X87, 0X88, 0X87, 0X78, 0X87, 0X8

6, //2012
0XA5, 0XB3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2013
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2014
0X95, 0XB4, 0X96, 0XA5, 0X96, 0X97, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //2015
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X87, 0X88, 0X87, 0X78, 0X87, 0X8

6, //2016
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2017
0XA5, 0XB4, 0XA6, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2018
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //2019
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X8

6, //2020
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2021
0XA5, 0XB4, 0XA5, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2022
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X79, 0X77, 0X8

7, //2023
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X9

6, //2024
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2025
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2026
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //2027
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X9

6, //2028
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2029
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2030
0XA5, 0XB4, 0X96, 0XA5, 0X96, 0X96, 0X88, 0X78, 0X78, 0X78, 0X87, 0X8

7, //2031
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X9

6, //2032
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2033
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X78, 0X88, 0X78, 0X87, 0X8

7, //2034
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2035
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X9

6, //2036
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

6, //2037
0XA5, 0XB3, 0XA5, 0XA5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2038
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2039
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X9

6, //2040
0XA5, 0XC3, 0XA5, 0XB5, 0XA5, 0XA6, 0X87, 0X88, 0X87, 0X78, 0X87, 0X8

6, //2041
0XA5, 0XB3, 0XA5, 0XB5, 0XA6, 0XA6, 0X88, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2042
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2043
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X88, 0X87, 0X9

6, //2044
0XA5, 0XC3, 0XA5, 0XB4, 0XA5, 0XA6, 0X87, 0X88, 0X87, 0X78, 0X87, 0X8

6, //2045
0XA5, 0XB3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X88, 0X78, 0X87, 0X8

7, //2046
0XA5, 0XB4, 0X96, 0XA5, 0XA6, 0X96, 0X88, 0X88, 0X78, 0X78, 0X87, 0X8

7, //2047
0X95, 0XB4, 0XA5, 0XB4, 0XA5, 0XA5, 0X97, 0X87, 0X87, 0X88, 0X86, 0X9

6, //2048
0XA4, 0XC3, 0XA5, 0XA5, 0XA5, 0XA6, 0X97, 0X87, 0X87, 0X78, 0X87, 0X8

6, //2049
0XA5, 0XC3, 0XA5, 0XB5, 0XA6, 0XA6, 0X87, 0X88, 0X78, 0X78, 0X87, 0X8

7 //2050

};

II.
再看一个简单算法

基于组件的C#农历算法

By talentz
From http://www.chinaitpower.com/A/2001-12-17/8126.html

// 下面是一个关于C#的农历算法
// 日期数据定义方法如下
// 前12个字节代表1-12月为大月或是小月,1为大月30天,0为小月29天,
// 第13位为闰月的情况,1为大月30天,0为小月29天,第14、15位为闰月的月
// 份,使用10进制表示。最后4位为当年家农历新年-即农历1月1日所在公历
// 的日期,如0131代表1月31日。
// 日期函数使用方式如下i公历年为要输入的公历年,i公历月为公历月,i公历日为
// 公历日,返回值为:属相 ,天干地支,农历年农历月农历日。

using System;

namespace 农历组件
{
public class 农历
{
private string[] m_str农历日历表;
private string[] m_str天干地支表;
private string m_str属相表;
private string m_str农历月表;
private string m_str农历日表;
private int m_i最大公历年份;
private int m_i最小公历年份;

public 农历()
{
m_str农历日历表 = new string[] {
"0100101101101080131",
"0100101011100000219",
"1010010101110000208",
"0101001001101050129",
"1101001001100000216",
"1101100101010000204",
"0110101010101040125",
"0101011010100000213",
"1001101011010000202",
"0100101011101020122",
"0100101011100000210",
"1010010011011060130",
"1010010011010000218",
"1101001001010000206",
"1101010101001050126",
"1011010101010000214",
"0101011010100000204",
"1001011011010020123",
"1001010110110000211",
"0100100110111070201",
"0100100110110000220",
"1010010010110000208",
"1011001001011050128",
"0110101001010000216",
"0110110101000000205",
"1010110110101040124",
"0010101101100000213",
"1001010101110000202",
"0100100101111020123",
"0100100101110000210",
"0110010010110060130",
"1101010010100000217",
"1110101001010000206",
"0110110101001050126",
"0101101011010000214",
"0010101101100000204",
"1001001101110030124",
"1001001011100000211",
"1100100101101070131",
"1100100101010000219",
"1101010010100000208",
"1101101001010060127",
"1011010101010000215",
"0101011010100000205",
"1010101011011040125",
"0010010111010000213",
"1001001011010000202",
"1100100101011020122",
"1010100101010000210",
"1011010010101070129",
"0110110010100000217",
"1011010101010000206",
"0101010110101050127",
"0100110110100000214",
"1010010110110000203",
"0101001010111030124",
"0101001010110000212",
"1010100101010080131",
"1110100101010000218",
"0110101010100000208",
"1010110101010060128",
"1010101101010000215",
"0100101101100000205",
"1010010101110040125",
"1010010101110000213",
"0101001001100000202",
"1110100100110030121",
"1101100101010000209",
"0101101010101070130",
"0101011010100000217",
"1001011011010000206",
"0100101011101050127",
"0100101011010000215",
"1010010011010000203",
"1101001001101040123",
"1101001001010000211",
"1101010100101080131",
"1011010101000000218",
"1011011010100000207",
"1001011011010060128",
"1001010110110000216",
"0100100110110000205",
"1010010010111040125",
"1010010010110000213",
"1011001001011100202",
"0110101001010000220",
"0110110101000000209",
"1010110110101060129",
"1010101101100000217",
"1001001101110000206",
"0100100101111050127",
"0100100101110000215",
"0110010010110000204",
"0110101001010030123",
"1110101001010000210",
"0110101100101080131",
"0101101011000000219",
"1010101101100000207",
"1001001101101050128",
"1001001011100000216",
"1100100101100000205",
"1101010010101040124",
"1101010010100000212",
"1101101001010000201",
"0101101010101020122",
"0101011010100000209",
"1010101011011070129",
"0010010111010000218",
"1001001011010000207",
"1100100101011050126",
"1010100101010000214",
"1011010010100000214"
};
m_str属相表 = "鼠牛虎兔龙蛇马羊猴鸡狗猪";
m_str农历月表 = "正二三四五六七八九十寒腊";
m_str农历日表 = "初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十";
m_i最大公历年份 = 2011;
m_i最小公历年份 = 1900;

string str天干 = "甲乙丙丁戊已庚辛壬癸";
string str地支 = "子丑寅卯辰巳午未申酉戌亥";
m_str天干地支表 = new string[60];
for (int i = 0; i < 60; i++)
{
m_str天干地支表[i] = str天干.Substring(i % 10, 1) + str地支.Substring(i % 12, 1);
}

}

public string 日期(int i公历年,
int i公历月,
int i公历日)
{
if ( (i公历年 < m_i最小公历年份) || (i公历年 > m_i最大公历年份) )
{ //如果不是有效公历日期,退出。
return "无效公历年份";
}

// 计算农历年
int i农历年;
int i农历月;
int i农历日;

i农历年 = i公历年;
// 农历新年月份
i农历月 = Convert.ToInt32((m_str农历日历表[i农历年 - m_i最小公历年份].Substring(15, 2)));
// 农历新年日子
i农历日= Convert.ToInt32((m_str农历日历表[i农历年 - m_i最小公历年份].Substring(17, 2)));;

if ( (i公历月 < i农历月) || ( (i公历月 == i农历月) && (i公历日 < i农历日)) )
{
i农历年--;
// 农历新年月份
i农历月 = Convert.ToInt32((m_str农历日历表[i农历年 - m_i最小公历年份].Substring(15, 2)));
// 农历新年日子
i农历日= Convert.ToInt32((m_str农历日历表[i农历年 - m_i最小公历年份].Substring(17, 2)));;
}

// 计算农历月
DateTime dt公历日期 = new DateTime(i公历年, i公历月, i公历日);
DateTime dt农历日期 = new DateTime(i农历年, i农历月, i农历日);
TimeSpan ts日期差 = dt公历日期 - dt农历日期;
int i天数 = ts日期差.Days;

i农历月 = 1;
i农历日 = 1;
bool b闰月 = false;
for (int i = 0; i < i天数; i++)
{
i农历日++;
if (i农历日 == 30 + Convert.ToInt32(m_str农历日历表[i农历年 - m_i最小公历年份].Substring(i农历月 - 1, 1)) ||
(b闰月 && ( i农历日 == 30 + Convert.ToInt32( m_str农历日历表[i农历年 - m_i最小公历年份].Substring(12, 1) ) )) )
{
if ( (b闰月 == false) && (i农历月 == Convert.ToInt32(m_str农历日历表[i农历年 - m_i最小公历年份].Substring(13, 2))) )
{
b闰月= true;
}
else
{
b闰月 = false;
i农历月++;
}
i农历日 = 1;
}
else
{
}
}

// 计算农历日
string str农历日 = m_str农历日表.Substring((i农历日 -1) * 2, 2);

// 计算农历月
string str农历月 = m_str农历月表.Substring(i农历月 - 1, 1) + "月";
if (b闰月)
{
str农历月 = "闰" + str农历月;
}

// 农历年
string str农历年 = Convert.ToString(i农历年, 10) + "年";

// 计算天干地支
string str天干地支 = m_str天干地支表[ (i农历年 - 4) % 60 ];

// 计算属相
string str属相 = m_str属相表.Substring((i农历年 - 4) % 12, 1);

// 返回农历日期
return str属相 + "," + str天干地支 + "," + str农历年 + str农历月 + str农历日;
}
}
}

III.
基于台湾的林洵贤先生编写的经典的200年JavaScript万年历的程序数不胜数,这里提个新的XML的

如何为live.com编写并添加自己的Gadget
By 维生素C.net
From http://www.cnblogs.com/lovewangshu/archive/2005/11/05/269332.html

IV.
eroica的改进JavaScript万年历的程序

多功能万年历原创代码解析(0)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(0)
发信站: 北大未名站 (2002年05月02日20:28:40 星期四) , 站内信件



早就听人说JavaScript是一种很“弱智”语言,只能实现一些简单的效果和功能。我以
前也是这样想,但曾经见到国外极为优秀的JS脚本,让我大开了眼界。而且,到目前为止我
深爱JS,甚至胜过C,说实话,目前会的程序语言也就是C和JS了。C是大一学的,当时是DOS
下的,学完甚觉无用,也确实一直没用上,现在忘了差不多了。自从去年学JS便发觉她易学
易用,直观实用,常常令人兴奋,于是一开始便喜欢上了她。

我早就想编一个万年历的程序放在网上,去年刚学完JavaScript是曾编了一个,凑合能
用,但算法麻烦,每一年的农历信息需要17个数来确定,另外节气计算公式也有点错误。后
来,我偶然在网上发现了由台湾的林洵贤先生编写的经典的200年JavaScript万年历,大大小
小的网站许多都用了林先生的年历(但大多数没说明版权),当时十分叹服。觉得自己和别
人毕竟差了好大一截。现在,终于,我竟已经写了自己的万年历,算法与林先生的截然不同
,适用年数近三千年,并且功能与准确度也是非林先生的万年历所能及的,如正规历书上记
载1985年春分是3月21日,这与本年历计算结果完全一致,而林先生的万年历则给出是3月20
日,其原因是我的算法考虑了岁差与章动,而林先生的则是用平节气的简单算法。

从编写第一个函数开始,到最近的一个BUG的去除,本年历断断续续地耗时一个多月(但
核心程序的编写不到一个月),要知道我还在念书,这些工作只能在课余完成。整个程序的
创作过程,有时是令人惊心动魄的,有时又是那么令人厌倦不堪,但无论如何,现在看来这
一切都是无法言传的,所有激情都将过去,一切又将从头开始。

未名BBS是我最常去的一个,Homepage版曾给了我很多帮助,各位网友也常常给我支持与
鼓励。所以我才决定从今天开始在未名公开这一两个月来辛苦编写的代码。希望各位大虾能
继续给我鼓励,并不断改进这些代码,使之不断完善,从而为广大网友服务。

最后,应当感谢曾次亮先生和Erling Poulsen,曾先生几十年的辛苦劳动使我得以将他
的节气计算方法公式化,而我的朔望交食程序则是在Erling Poulsen的程序上加以简化和应
用的。另外,部分节日我也参考了林洵贤先生的万年历,在此也表示感谢。

我想应该是迄今为止最全的万年历,从公元前850年(我国历法开始)—公元2100年,公
历(包括格里历和儒略历)与农历对照,星期,星座,生肖,儒略日,年月日时干支,24节气的
交节时刻(最大误差10分钟),以及月亮朔望的时刻(最大误差3分钟),还有日月食预报功
能。梅雨,夏三伏,冬三九也准确显示。当然,还会显示公历节日,传统节日,名人纪念日,以及生
日等等。后来又增加了历史年号(目前至隋朝)、个人日记、人体生物周期节律、倒计时设
置等更加实用的功能。这样,本年历就几乎涵盖了网上大部分日期时间类的脚本功能,更何
况实现了简单脚本无法实现的功能呢?

完全用JavaScript开发,纯文本文件的大小不过20KB,代码中详细列有各种有关日期的
函数,比JavaScript内置的日期函数功能强大得多,可以根据需要随时调用。在此基础上利用FS
COMMAND技术可以作成Flash应用程序。

全代码完全手写,没有调用任何JavaScript内置的日期函数(除非调用当前时刻),重
新编制各种日期时间函数,思路新颖,计算方法简洁。

由于刚刚制作并初步调试完成,界面还很粗糙,但这已经断断续续花费了我很多的时间
,待日后进一步完善。

声明

1、本代码由aqyw(eroica)原创,在未名BBS的Homepage版首次公开,欢迎大家引用和改
进,但希望大家能珍惜作者的劳动,最好能注明出处。

2、由于时间仓促,代码可能在一些细节上不太优化,有些功能没继续实现(如儒略历与
格里历的互换等),或者变量和函数的名称可笑而不确切,但由于精力和时间关系,作者没
能完善,还请大家见谅。

3、本代码仅供参考,个别地方有误敬请大家指出。大家在实际应用中可以按需要引用某
些原文件(如只用阴历,或只用生物钟等,有点象C中的头文件)。

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]
※ 修改:·eroica 於 05月02日20:33:05 修改本文·[FROM: 210.31.66.32]

多功能万年历原创代码解析(1)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(1)
发信站: 北大未名站 (2002年05月02日20:36:55 星期四) , 站内信件

本代码由math.js、solar.js、sterm.js、ganzhi.js、lunar.js、string.js、ftvl.js、ni
anhao.js、cookies.js、humancyc.js、float.js、diary.js、countdown.js及dw.js等js文
件组成。下面就分别介绍之。
(一)数学函数集——math.js
我想不用过多解释了,大家肯定看得懂。此函数集只是为了后面引用时书写方便而已。
PI()——返回圆周率3.141592653589793
sin(x)——返回x的正弦
cos(x)——返回x的余弦
abs(x)——返回x的绝对值
floor(x)——返回x的下界取整值
round(x)——返回x的四舍五入值
tail(x)——返回x的小数尾数,若x为负值,则是1-小数尾数
rem(x,w)——返回x对w的广义求余

代码:

//-------数学函数------//

function PI(){
return Math.PI;
}

function sin(x){
return Math.sin(x);
}

function cos(x){
return Math.cos(x);
}

function abs(x){
return Math.abs(x);
}

function floor(x){
return Math.floor(x);
}

function round(x){
return Math.round(x);
}

function tail(x){
return x-floor(x);
}

function rem(x,w){ //广义求余
return tail(x/w)*w;
}

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]
※ 修改:·eroica 於 05月02日20:39:09 修改本文·[FROM: 210.31.66.32]

多功能万年历原创代码解析(2)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(2)
发信站: 北大未名站 (2002年05月02日20:41:46 星期四) , 站内信件

(二)公历函数集——solar.js

关于公历的一些算法和公式偶在几年前就想出了,但今年寒假回家发现有些错误,后来终于
弄对了。

先介绍一些函数的用途:

ifGr(y,m,d,opt)——判断y年m月(1,2,..,12,下同)d日是Gregorian历还是Julian历(opt=1
,2,3分别表示标准日历,Gregorge历和Julian历),是则返回1,是Julian历则返回0,若是Gr
egorge历所删去的那10天则返回-1
D0(y,m,d)——返回阳历y年m月d日的日差天数(在y年年内所走过的天数,如2000年3月1日为
61)
antiD0(y,x)——返回阳历y年日差天数为x时所对应的月日数(如y=2000,x=274时,返回10
01(表示10月1日,即返回100*m+d))
D(y)——返回y年的年差天数(y年1月1日距相应历种的1年1月1日的天数)
erD(y,m,d)——返回等效标准天数(y年m月d日相应历种的1年1月1日的等效(即对Gregorian
历与Julian历是统一的)天数)
JD(y,m,d,h,min,sec,zone)——返回儒略日(zone时区y年m月d日h时min分sec秒距儒略历公
元前4713年1月1日格林尼治时间正午12时的天数) Day(y,m,d)——返回星期数(y年m月d日
的星期数,如星期日为0)
sZod(m,d)——返回星座数(m月d日的星座序号,如摩羯座为0)

代码:


//---------公历--------//

//判断Gregorian历还是Julian历
function ifGr(y,m,d,opt){ //阳历y年m月(1,2,..,12,下同)d日,opt=1,2,3分别表示标准
日历,Gregorge历和Julian历

if(opt==1){
if(y>1582||(y==1582&&m>10)||(y==1582&&m==10&&d>14))
return(1); //Gregorian
else
if(y==1582&&m==10&&d>=5&&d<=14)
return(-1); //空
else
return(0); //Julian
}

if(opt==2)
return(1); //Gregorian
if(opt==3)
return(0); //Julian

}

//日差天数
function D0(y,m,d){
var ifG=ifGr(y,m,d,1);
var monL=new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);
if(ifG)
if((y%100!=0&&y%4==0)||(y%400==0))
monL[2]+=1;
else ;
else
if(y%4==0)
monL[2]+=1;
else ;
var v=0;
for(var i=0;i<=m-1;i++){
v+=monL[i];
}
v+=d;
if(y==1582){
if(ifG==1)
v-=10;
if(ifG==-1)
v=1/0; //infinity
}
return v;
}

//反日差天数
function antiD0(y,x){
var m=1;
for(var j=1;j<=12;j++){
var mL=D0(y,j+1,1)-D0(y,j,1);
if(x<=mL||j==12){
var m=j;
break;
}
else
x-=mL;
}
return 100*m+x;
}

//年差天数
function D(y){
var v=(y-1)*365+floor((y-1)/4); //Julian的年差天数
if(y>1582)
v+=-floor((y-1)/100)+floor((y-1)/400); //Gregorian的年差天数
return v;
}

//等效标准天数
function erD(y,m,d){
var v=(y-1)*365+floor((y-1)/4)+D0(y,m,d)-2; //Julian的等效标准天数
if(y>1582)
v+=-floor((y-1)/100)+floor((y-1)/400)+2; //Gregorian的等效标准天数
return v;
}

//儒略日
function JD(y,m,d,h,min,sec,zone){
var ifG=ifGr(y,m,d,1);
var jt=(h+(min+sec/60)/60)/24-0.5-zone/24;
var jd=(ifG)?(erD(y,m,d)+1721425+jt):(erD(y,m,d)+1721425+jt);//儒略日
return jd;
}

//星期
function Day(y,m,d){
return erD(y,m,d)%7;
}

//星座
function sZod(m,d){
var zodd=new Array(1222,122,222,321,421,522,622,722,822,922,1022,1122,1222);
if((100*m+d)>=zodd[0]||(100*m+d) var i=0;
else
for(var i=1;i<12;i++){
if((100*m+d)>=zodd[i]&&(100*m+d) break;
}
return i;
}

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]
※ 修改:·eroica 於 05月02日20:44:45 修改本文·[FROM: 210.31.66.32]

多功能万年历原创代码解析(3)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(3)
发信站: 北大未名站 (2002年05月02日21:00:39 星期四) , 站内信件

(二)节气函数集——sterm.js

节气是最让我头疼的问题,我几乎想了一个寒假都没能想出一个比较准确的计算公式。我
以前的算法和林洵贤先生的200年日历中的一样,都是用“平气”(即把地球绕日轨道完全2
4等分,且认为地球公转周期恒定不变),所以时间跨度两百年以上就有误差了,林先生的日
历也有个别错误。其原因在于地球公转周期会随时间变化,而且地球自转轴受太阳、行星及
月球影响绕北天极转动,这些因素称为岁差和章动。当初我真的快要放弃了,但回到北京会
马上出现了转机。
那天去西单图书大厦,偶然发现了曾次亮先生的《四千年气朔交食速算法》,其中就给
出了节气的精确算法!我花了25元钱买下。但曾先生的书都是列了许多表格中的数据进行计
算的,我不得不把表格中的数据用手工进行拟合,好不容易才一点一点凑出了计算公式。想
来真是不容易啊!

只有一个函数:

S(y,n,pd)——返回y年第n个节气(如小寒为1)的D0(日差天数)值(pd取值为0或1,分别
表示平气和定气)

代码://节气函数
function S(y,n,pd){ //pd取值为0或1,分别表示平气和定气,该函数返回节气的D0值
var juD=y*(365.2423112-6.4e-14*(y-100)*(y-100)-3.047e-8*(y-100))+15.218427*n+1
721050.71301;//儒略日
var tht=3e-4*y-0.372781384-0.2617913325*n;//角度
var yrD=(1.945*sin(tht)-0.01206*sin(2*tht))*(1.048994-2.583e-5*y);//年差实均数
var shuoD=-18e-4*sin(2.313908653*y-0.439822951-3.0443*n);//朔差实均数
var vs=(pd)?(juD+yrD+shuoD-erD(y,1,0)-1721425):(juD-erD(y,1,0)-1721425);
return vs;
}

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]

多功能万年历原创代码解析(4)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(4)
发信站: 北大未名站 (2002年05月03日09:18:42 星期五) , 站内信件

(四)干支函数集——ganzhi.js

根据古代术数,年干支以立春为界,而月干支按节气月(从立春到雨水为一月,余类推
)赋予,日干支以子时(从现代时间23时开始)为界。

古人是用口诀来推算月和时的干支的,后来我都将它们公式化了。年和日的干支只能自
己凑公式了。


各函数的功用如下:

gan(x)——返回甲子数x对应的天干数(如33为3)
zhi(x)——返回甲子数x对应的地支数(如33为9)
yGz(y,m,d,h)——返回y年m月d日h时的年干支数(1-60)
mGz(y,m,d,h)——返回y年m月d日h时的月干支数(1-60)
dGz(y,m,d,h)——返回y年m月d日h时的日干支数(1-60)
hGz(y,m,d,h)——返回y年m月d日h时的时干支数(1-60)

代码:

//天干
function gan(x){
return x%10;
}

//地支
function zhi(x){
return x%12;
}

//年干支
function yGz(y,m,d,h){
if((D0(y,m,d)+h/24) y-=1;
return round(rem(y-3,60));
}

//月干支
function mGz(y,m,d,h){

var sN0=2*m-2;
var sDt0=S(y,sN0,1);
var sD0=antiD0(y,floor(sDt0));
var sM0=floor(sD0/100);
var sDate0=sD0%100+tail(sDt0);

var sN1=2*m-1;
var sDt1=S(y,sN1,1);
var sD1=antiD0(y,floor(sDt1));
var sM1=floor(sD1/100);
var sDate1=sD1%100+tail(sDt1);

var sN2=2*m;
var sDt2=S(y,sN2,1);
var sD2=antiD0(y,floor(sDt2));
var sM2=floor(sD2/100);
var sDate2=sD2%100+tail(sDt2);

var sN3=2*m+1;
if(sN3>24)
sN3-=24;
var sDt3=S(y,sN3,1);
var sD3=antiD0(y,floor(sDt3));
var sM3=floor(sD3/100);
var sDate3=sD3%100+tail(sDt3);

if(sM0==m){
sN2=sN1; sN1=sN0;
sDt2=sDt1; sDt1=sDt0;
sDate2=sDate1; sDate1=sDate0;
}

if(sM3==m){
sN1=sN2; sN2=sN3;
sDt1=sDt2; sDt2=sDt3;
sDate1=sDate2; sDate2=sDate3;
}

sN1=rem(sN1-1,24)+1;
sN2=rem(sN2-1,24)+1;

var mL=D0(y,m,31)-D0(y,m,0);
if(sDate2>mL)
sDate2-=mL;

var jqDate=(sN1%2==1)?sDate1:sDate2; //"节气"(n为奇数)所在的阳历日数

var gzM=((d+h/24) if(gzM<=0)
gzM+=12;
return round(rem(12*gan(yGz(y,m,d))+gzM-10,60));
}

//日干支
function dGz(y,m,d,h){
var gzD=(h<23)?erD(y,m,d):erD(y,m,d)+1;
return round(rem(gzD+15,60));
}

//时干支
function hGz(y,m,d,h){
var v=12*gan(dGz(y,m,d,h))+floor((h+1)/2)-11;
if(h==23)
v-=12;
return round(rem(v,60));
}

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]

多功能万年历原创代码解析(5)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(5)
发信站: 北大未名站 (2002年05月03日10:02:27 星期五) , 站内信件

(五)农历函数集——lunar.js

农历也是让人费尽脑汁的问题。
编写阳历的程序不难,因为阳历历法较简单,即使有闰月,也是很规则的。而阴历则不
然,
其难有三:(一)月大月小无规律。今年的一月可能是大月,但到了明年也可能是小月。一
月月大,但二月可能月大,也可能月小,月大月小既非穿插,亦非连续,唯“乱”字可谓之
矣!公认的阴历是经过观测朔望及复杂的天文计算得出的!(二)闰月无规律,唯一的规律
就是:19年7闰。具体闰在哪个月需要结合“节气”推知(无“中气”之月设闰)。(三)阴
阳历对应无规律,此点自然明了,不必多说。

好在我寒假时偶然在国外网站上发现了Erling Poulsen用JS编写的一个计算各个月朔望
时刻及判断日月食的小程序,便如获至宝,将其代码打印出来研究,得出算法和公式,然后
又将其进一步精简。这样每个阴历月的初一日我就能精确得到了,因此大小月也就能判断了
,下面的问题就只是如何判断闰月了。

我首先仍想编个程序,按照农历历法的规则让程序自动生成闰月。所依据的法则是“无
中气置闰法”:不包含中气的月份作为前一个月的闰月。因为好在节气我也能够精确计算,
所以我觉得这个思路应当可行。我成功地按照这个想法写出了“完全自然生成”的农历,但
很快便发现如下问题:

1、“无中气置闰法”也有例外(我不知是为什么)!如:1985年正月无中气,理应是闰
月,但实际不是。
2、当节气在两日的交界处时,计算的误差(尽管较小)也显得重要了。
3、历代对闰月的安插也不尽相同。秦代以前,曾把闰月放在一年的末尾,叫做“十三月
”。汉初把闰月放在九月之后,叫做“后九月”。到了汉武帝太初元年,又把闰月分插在一
年中的各月。

所以,我看到闰月无论如何也不可能“完全自然生成”了,于是想到类似林先生的方法
,用数组存储各年的农历信息。林先生用16进制来储存,每年用了6位数。而现在我只需要知
道的是每年的闰月信息,所以每年只需用1个数字即可!我用的是字符串来储存,因为JS的字
符串处理能力也是很强大的。

除此优点外,这种方法十分利于添加和输入。因为每年只需输入相应的闰月数(16进制
,无闰月则为0)即可。从公元前850年到公元后2100的闰月数是我亲自用手输入的(当然我
用JS编了一个输入的程序,既快捷,又能避免错误)。原则上说,大家还可以无限添加年代
,我因为时间和精力有限,所以只达到公元前850年(这些闰月数据来自曾先生的《四千年气
朔交食速算法》)。

函数说明:

leapMon(y)——返回农历y年的闰月数,若无闰则返回0(如2001年为4)
lunDate(y,m,d)——返回y年m月d日农历日数及日月食信息的函数,如-324.57923415,负号
表示闰月,百位3表示月偏食(2为月全食,1为日食0为无食),百位及十位表示日数,小数部分是
朔望时刻(单位为天,若该天不朔或望则小数部分为零)
lunMon(y,m,d)——返回y年m月d日农历月数,若是闰月则取负值,如-12表示闰十二月

代码:

//----------------------------------农历闰月信息--------------------------------
----------
var starY=-849; //记录从公元前850年开始
var leapM='0c0080050010a0070030c0080050010a0070030c0080050020a0070030c0080050020
a0070030c0090050020a0070030c0090050020a0060030c0060030c00900600c0c0060c00c00c00c
0c000600c0c0006090303030006000c00c060c0006c00000c0c0c0060003030006c00009009c0090
c00c009000300030906030030c0c00060c00090c0060600c0030060c00c003006009060030c00600
60c0090900c00090c0090c00c006030006060003030c0c00030c0060030c0090060030c0090300c0
080050020a0060030c0080050020b0070030c0090050010a0070030b0090060020a0070040c00800
50020a0060030c0080050020b0070030c0090050010a0070030b0090060020a0070040c008005002
0a0060030c0080050020b0070030c0090050000c0090090900900909009009009090090090900900
90090900900909009009009090090090900900900909009009090090090900900900909009009090
09009009090090090900900900909009009090060030c0090050010a0070030b0080050010900700
40c0080050020a0060030c0090040010a0060030c0090050010a0070030b0080050010a008005001
090050020a0060030c0080040010a0060030c0090050010a0070030b0080050010a0070030b00800
5001090070040c0080050020a0060030c0080040010a0060030c0090050010a0070030b008005001
090070040c0080050020a0060030c0080040010a0060030c0090050010a0060030c0090050010a00
70030b008005001090070040c0080050020a0060030c0080040010a0070030b0080050010a007004
0c0080050020a0060030c0080040010a0070030c0090050010a0070030b0080050020a0060030c00
80040010a0060030c0090050050020a0060030c0090050010b0070030c0090050010a0070040c008
0040020a0060030c0080050020a0060030c0090050010a0070030b0080040020a0060040c0090050
020b0070030c00a0050010a0070030b0090050020a0070030c0080040020a0060030c0090050010a
0070030c0090050030b007005001090050020a007004001090060020c0070050c0090060030b0080
040020a0060030b0080040010a0060030b0080050010a0050040c0080050010a0060030c00800500
10b0070030c007005001090070030b0070040020a0060030c0080040020a0070030b0090050010a0
060040c0080050020a0060040c0080050010b0070030c007005001090070030c0080050020a00700
30c0090050020a0070030c0090050020a0060040c0090050020a0060040c0090050010b0070030c0
080050030b007004001090060020c008004002090060020a008004001090050030b0080040020a00
60040b0080040c00a0060020b007005001090060030b0070050020a0060020c00800400209007003
0c008005002090070040c0080040020a0060040b0090050010a0060030b0080050020a0060040c00
80050010b00700300108005001090070030c0080050020a007003001090050030a0070030b009005
0020a0060040c0090050030b0070040c0090050010c0070040c0080060020b00700400a090060020
b007003002090060020a005004001090050030b007004001090050040c0080040c00a0060020c007
005001090060030b0070050020a0060020c008004002090060030b008004002090060030b0080040
020a0060040b0080040010b0060030b0070050010a00600400207005003080060040030700500307
006004003070050030800600400307005004090060040030700500409006005002070050030a0060
05003070050040020600400206005003002060040030700500409006004003070050040800700500
3080050040a006005003070050040020600500308005004002060050020700500400206005003070
06004002070050030800600400307005004080060040a00600500308005004002070050040900600
4002060050030b006005002070050030800600400307005004080060040030700500408006004002
0';//-849-2100
function leapMon(y){
var v=leapM.charAt(y-starY);
if(v=='a')
v=10;
if(v=='b')
v=11;
if(v=='c')
v=12;
return parseInt(v);
}
//------------------------------------------------------------------------------
----------

//------农历及日月食------//
//角度函数
function ang(x,t,c1,t0,t2,t3){
return tail(c1*x)*2*PI()+t0-t2*t*t-t3*t*t*t;
}

//返回农历日数及日月食信息的函数,如-324.57923415,负号表示闰月,百位3表示月偏食
(2为月全食,1为日食0为无食),百位及十位表示日数,小数部分是朔望时刻(单位为天,若该天
不朔或望则小数部分为零)

function lunDate(y,m,d){
var t=(y-1899.5)/100;
var ms=floor((y-1900)*12.3685);
var rpi=180/PI();
var zone=8; //时区
var f0=ang(ms,t,0,0.75933,2.172e-4,1.55e-7)+0.53058868*ms-8.37e-4*t+zone/24+0.
5;
var fc=0.1734-3.93e-4*t;
var j0=693595+29*ms;
var aa0=ang(ms,t,0.08084821133,359.2242/rpi,0.0000333/rpi,0.00000347/rpi);
var ab0=ang(ms,t,7.171366127999999e-2,306.0253/rpi,-0.0107306/rpi,-0.00001236/
rpi);
var ac0=ang(ms,t,0.08519585128,21.2964/rpi,0.0016528/rpi,0.00000239/rpi);
var leap=0; //闰月数,0则不闰
var ecli=0; //日月食
var lunD=-1; //农历日数
var shuoD=0; //本阴历月的阴历朔日数
var shuoT=0; //本阴历月的朔时刻
var wangD=0; //本阴历月的望时刻
var wangT=0; //本阴历月的阴历望日数

for(var k=-1;k<=13;k+=0.5){ //k=整数为朔,k=半整数为望
var aa=aa0+0.507984293*k;
var ab=ab0+6.73377553*k;
var ac=ac0+6.818486628*k;
var f1=f0+1.53058868*k+fc*sin(aa)-0.4068*sin(ab)+0.0021*sin(2*aa)+0.0161*sin
(2*ab)+0.0104*sin(2*ac)-0.0074*sin(aa-ab)-0.0051*sin(aa+ab);
var j=j0+28*k+f1; //朔或望的等效标准天数及时刻

//记录当前日期的j值
var lunD0=erD(y,m,d)-floor(j); //当前日距朔日的差值
if(k==floor(k)&&lunD0>=0&&lunD0<=29){
var k1=k; //记录当前时间对应的k值
shuoT=tail(j);
lunD=lunD0+1;
}
if(k==(k1+0.5)){
wangT=tail(j);
wangD=floor(j)-(erD(y,m,d)-lunD+1)+1;
}

//判断日月食
if((lunD==1&&k==k1)||(lunD==wangD&&k==(k1+0.5))){
if(abs(sin(ac))<=0.36){
var s=5.19595-0.0048*cos(aa)+0.002*cos(2*aa)-0.3283*cos(ab)-0.006*cos(aa
+ab)+0.0041*cos(aa-ab);
var r=0.207*sin(aa)+0.0024*sin(2*aa)-0.039*sin(ab)+0.0115*sin(2*ab)-0.00
73*sin(aa+ab)-0.0067*sin(aa-ab)+0.0117*sin(2*ac);
var p=abs(s*sin(ac)+r*cos(ac));
var q=0.0059+0.0046*cos(aa)-0.0182*cos(ab)+0.0004*cos(2*ab)-0.0005*cos(a
a+ab);
if(p-q<=1.5572){
ecli=1; //日食
if(k!=floor(k)){
if(p+q>=1.0129)
ecli=3; //月偏食
else
ecli=2; //月全食
}
}
}
}
}
//k循环结束

var v=lunD; //返回值
if(v==1)
v+=shuoT //朔日则返回朔的时刻
if(v==wangD)
v+=wangT; //望日则返回望的时刻

return(v+ecli*100)
}

function lunMon(y,m,d){
var lunDt=lunDate(y,m,d);
var lunD=floor(lunDt-floor(lunDt/100)*100); //农历日数
var leapN=0; //从当年到-849年的总闰月数
for(var i=-849;i<=y;i++){
if(leapMon(i)!='0')
leapN++;
}
var MonN=round((erD(y,m,d)-erD(-849,1,21)-lunD)/29.530588)-leapN //从当年到-8
49年的有效总月数(扣除闰月)

if(y<=240) MonN++;
if(y<=237) MonN--;
if(y<24) MonN++;
if(y<9) MonN--;
if(y<=-255) MonN++;
if(y<=-256) MonN+=2;
if(y<=-722) MonN++; //历史上的修改月建

var lunM=round(rem(MonN-3,12)+1);
if(lunM==leapMon(y-1)&&m==1&&d lunM*=-1; //如果y-1年末是闰月且该月接到了y年,则y年年初也是闰月
else{
if(lunM==leapMon(y))
lunM*=-1;
else{
if(lunM lunM++; //如果y年是闰月但当月未过闰月则前面多扣除了本年的闰月,这里应当
补偿
lunM=round(rem(lunM-1,12)+1);
}
}

return lunM;
}

备注:

现行农历采用的是夏历(即建寅为正),所以本年历主要采用夏历,但由于历史上改朝
换代或君王改换纪元等原因,曾有多次修改月建,在本年历中未作特别说明,现说明如下:
i)公元前256年(秦襄昭王52年)采用秦历,此前一直采用古周历(但春秋战国时各国历法不
一,较为混乱)。秦历以十月为岁首,“后九月”为闰月。
ii)公元前105年,西汉太初元年五月改历,以正月为岁首,该年有十五个月(从十月、十一
月、十二月、一月、二月、......十二月)。
iii)公元9年,新朝王莽始建国1年,以12月为正月(丑月),故上一年无“十二月”。
iv)公元23年,淮阳王改元更始,复用因寅正,以地皇十一月为更始1年的十月,故是年有两
个十月。
v)三国魏青龙5年(公元237年)三月,改元景初,建丑为正,以三月为四月,四月为五月,
...,十二月为正月。而景初三年十二月,魏复寅正,故是年有两个十二月。
vi)周武则天天授一年(载初1年,公元689年)十一月,该行周历子正。以十一月为岁首,该
为载初1年正月,故乙丑年只有十个月。
vii)久视1年十月复寅正,以正月为十一月,故是年有14个月。
viii)唐上元2年(公元761年)九月去年号,但称元年。以建子为正,月以所建辰为名,原十
月称亥月,原十一月称子月(岁首),...,原三月为辰月。而建巳月复寅正,恢复原月名,
仍称四月。故辛丑年无十一月、十二月。壬寅年有十四个月。
另外,应当指出,本年历采用的都是实朔,而从春秋战国一直到唐初用的都是平朔,所以有
在阴历日期上会有一日之差,应当说这是古人的不足。不过,古人常用日月食来校正日期(
所谓观象授时),因而此时与本年历是吻合的。

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.32]

多功能万年历原创代码解析(补5.5)发信人: eroica (aqyw), 信区: Homepage
标 题: 多功能万年历原创代码解析(补5.5)
发信站: 北大未名站 (2002年05月04日13:38:57 星期六) , 站内信件

不好意思,这个函数集忘贴了

(续五)转换成字符串的函数集——string.js

dToStr(dv)——将单位为天的纯小数转换成如同"2:07"的时间格式
dayStr(v)——将星期数转换成星期汉字,如0为"日"
szodStr(v)——将星座数转换成星座汉字,如0为"摩羯座"
gzStr(v)——将干支数转换成干支汉字,如0为"癸亥"
zodStr(v)——将生肖数转换成生肖汉字,如0为"猪"
lunMStr(v)——将农历月数转换成农历月的汉字,如-12为"闰十二月"
lunDStr(v)——将农历日数转换成农历日的汉字,如5为"初五"
sStr(v)——将节气序数转换成节气汉字名称,如24为"冬至"
ifgStr(v)——将公历类型数转换成公历类型汉字名称,如0为"儒略历",若-1则弹出"公历历
法去掉了1582年10月5日至10月14日,因而这十天在历史上不存在!"提示窗口
shwStr(v1,v2)——将农历v1日及v2尾数(由lunDate(y,m,d)所得到,若非朔望则v2=0)转换
成"朔"或"望",若非朔望则返回空字符串
ecliStr(v)——将日月食数(由lunDate(y,m,d)所得到)转换成汉字,如2为"月全食",若无
日月食则返回空字符串

代码:

//--------转换成字符串的函数--------//

//将单位天的纯小数转换成如同5:08的时间格式
function dToStr(dv){
var h=floor(dv*24);
var min=floor((dv*24-h)*60);
if(min<10)
min='0'+min;
return h+':'+min;
}

//星期
function dayStr(v){
return '日一二三四五六'.charAt(v%7);
}

//星座
function szodStr(v){
return '摩羯宝瓶双鱼白羊金牛双子巨蟹狮子处女天秤天蝎射手'.substring(2*v,2*v+2)
+'座';
}

//干支
function gzStr(v){
return '癸甲乙丙丁戊己庚辛壬'.charAt(v%10)+'亥子丑寅卯辰巳午未申酉戌'.charAt(v
%12);
}

//生肖
function zodStr(v){
return '猪鼠牛虎兔龙蛇马羊猴鸡狗'.charAt(v);
}

//农历月数
function lunMStr(v){
var v0=abs(v);
var str='一二三四五六七八九十';
var vstr=str.charAt((v0-1)%10);
if(v0>10)
vstr='十'+vstr;
if(v0==1)
vstr='正';
if(v<0)
vstr='闰'+vstr;
return vstr;
}

//农历日数
function lunDStr(v){
var str='十一二三四五六七八九初十廿三';
var vstr=str.charAt(floor(v/10)+10)+str.charAt(v%10);
if(v==10)
vstr='初十';
return vstr;
}

//节气
function sStr(v){
return '小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋
分寒露霜降立冬小雪大雪冬至'.substring(2*v-2,2*v);
}

//公历类型
function ifgStr(v){
if(v==-1){
alert('公历历法去掉了1582年10月5日至10月14日,因而这十天在历史上不存在!');
return('不存在');
}
else
return (v)?'格里历':'儒略历';
}

//朔望
function shwStr(v1,v2){
var str='';
if(v1==1)
str=dToStr(v2)+'朔';
else
if(v2)//(v1==15||v1==16)&&v2)
str=dToStr(v2)+'望';
else;
return str;
}

//日月食
function ecliStr(v){
var str='';
if(v==1)
str='日食';
if(v==2)
str='月全食';
if(v==3)
str='月偏食';
return str;
}

--
┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐
┆怀藏奥妙独一角 网络精华数万家┆
└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 210.31.66.30]

(按:以下省略)

V.
其它高精度算法

VSOP87 Functions used to Compute Planetary Positions

http://www.freevbcode.com/ShowCode.Asp?ID=464
http://cosoft.org.cn/html/osl/projects.php?group_id=12522
http://hubble.lamost.org/alg.htm



<< Home

This page is powered by Blogger. Isn't yours?