#ifndef TERM_H
#define TERM_H
#include <string>
using namespace std;
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
struct Term
{
char month; // 1-12
char day; // 1-31
char h; // 0-23
char m; // 0-59
char s; // 0-59
};
struct LunarSolarDate
{
int year; // 公历年
char month; // 1-12
char day; // 1-31 公历日
char week; // 0-6
int lunarY; // 农历年,首尾法
char lunarM; // 1-12
char lunarD; // 1-30
bool isLeapM; // 是否闰月
long monCyl; // 干支 月,首尾法,干支月和农历月完全吻合
long dayCyl; // 干支 日
long cycTermM; // 干支 月,以时令法,以节气开始至下个节气前一天为干支月
long cycTermY; // 干支 年,时令法
};
struct MyDate
{
int year;
char month;
char day;
bool isLeap;
long monCyl;
long dayCyl;
};
// 根据输入的公历年号和月份,返回该月的天数
int MonthDays(int year, int month);
// 根据输入的公历日期,返回对应的星期
int WeekDay(int year, int month, int day);
// 传回农历 y年的总天数
long LunarYearDays(long y);
// 传回农历 y年闰月的天数
long LunarLeapDays(long y);
// 传回农历 y年闰哪个月 1-12 , 没闰传回 0
long LunarLeapMonth(long y);
// 传回农历 y年m月的总天数
long LunarMonthDays(long y, long m);
// 传入 offset 传回干支, 0=甲子
void Cyclical(long offset, char GanZhi[5]);
// 根据公历年月日,返回农历信息 dateOut
void Lunar(int year, int month, int day, MyDate & dateOut);
// 返回农历日day的汉子表示, day 取值返回 1-30
string LunarDay(char day);
/*
* 全局变量声明
*/
extern char solarTerm[][5];
extern int baseYear;
extern int TotalYear;
extern long lunarInfo[];
class CCalendar
{
public:
CCalendar(int year, int month);
// 公历的 y 年 m 月 d 日 是否为农历节气,如果是,则返回 0 - 23。否则返回 -1。
int IsTerm(int y, int m, int d, Term & term);
int GetTerm(int y, int n, Term & term);
// 公历的 y 年 m 月 d 日 以时令法 划分的 干支月
int GetTermMonth(int y, int m, int d);
// 生成时令法的干支年月
int GenTermGanzhi(LunarSolarDate & ld);
int GenTermGanzhi(int y, int m, int d, int &cycY, int &cycM);
void OutPut();
protected:
private:
LunarSolarDate m_day[31]; // 公历月最多31天
char m_dayNum; // 公历月的天数
char m_month; // 公历月 1-12
int m_year; // 公历年
};
#endif
/
#include "stdafx.h"
#include "term.h"
#include <math.h>
#include <string.h>
// 公历平年每月的天数
char g_solarMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
// 天干, 地支
char Gan[][3] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
char Zhi[][3] = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
char solarTerm[][5] ={"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
int baseYear = 1899; // 公历 1900.1.1对应的农历:1899.12.1
long lunarInfo[] = {
0x0ab50,
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2, // 农历1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977, // 1910
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970, // 1920
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950, // 1930
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557, // 1940
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0, // 1950
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6, // 1970
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0, // 1990
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5, // 2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930, // 2010
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530, // 2020-2029
0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0, // 2040-2049
0x14B63,0x09370,0x049F8
};
int TotalYear = sizeof(lunarInfo)/sizeof(long) + baseYear;
Term g_term[][24] = {
{ { 1, 5,19, 8,46}, { 1,20,12,27,41}, { 2, 4, 6,47,50}, { 2,14,10,51,17}
, { 3, 6, 0,42,22}, { 3,21, 1,32,12}, { 4, 5, 5,30,29}, { 4,20,12,29,47}
, { 5, 5,22,44, 1}, { 5,21,11,33,54}, { 6, 6, 2,49,23}, { 6,21,19,28,24}
, { 7, 7,13, 2,23}, { 7,23, 6,21,12}, { 8, 7,22,49,07}, { 8,23,13,26,57}
, { 9, 8, 1,44,39}, { 9,23,11, 9,02}, {10, 8,17,26,29}, {10,23,20,35, 3}
, {11, 7,20,42,28}, {11,22,18,14,32}, {12, 7,13,38,21}, {12,22,07,38,26}
} // 以上为 2010
,{{ 1, 6, 0,54,36}, { 1,20,18,18,31}, { 2, 4,12,32,55}, { 2,19, 8,25,19}
, { 3, 6, 6,29,58}, { 3,21, 7,20,44}, { 4, 5,11,11,58}, { 4,20,18,17,27}
, { 5, 6, 4,23,14}, { 5,21,17,21,11}, { 6, 6, 8,27,21}, { 6,22, 1,16,30}
, { 7, 7,18,42, 1}, { 7,23,12,11,49}, { 8, 8, 4,33,27}, { 8,23,19,20,38}
, { 9, 8, 7,34,12}, { 9,23,17, 4,37}, {10, 8,23,19, 4}, {10,24, 2,30,17}
, {11, 8, 2,34,54}, {11,23, 0, 7,47}, {12, 7,19,28,59}, {12,22,13,30, 1}
} // 以上为 2011
,{{ 1, 6, 6,43,54}, { 1,21, 0, 9,48}, { 2, 4,18,22,21}, { 2,19,14,17,34}
, { 3, 5,12,21, 2}, { 3,20,13,14,25}, { 4, 4,17, 5,36}, { 4,20, 0,12, 4}
, { 5, 5,10,19,40}, { 5,20,23,15,31}, { 6, 5,14,25,53}, { 6,21, 7, 8,48}
, { 7, 7, 0,40,43}, { 7,22,18, 0,52}, { 8, 7,10,30,32}, { 8,23, 1, 6,50}
, { 9, 7,13,29, 0}, { 9,22,22,49, 0}, {10, 8, 5,11,43}, {10,23, 8,13,33}
, {11, 7, 8,25,56}, {11,22, 5,50, 7}, {12, 7, 1,18,55}, {12,21,19,11,36}
} // 以上为 2012
};
int g_baseY = 2010; // 公历年
int g_maxY = sizeof(g_term)/sizeof(Term)/24 + g_baseY;
CCalendar::CCalendar(int year, int month):m_year(year), m_month(month)
{
m_dayNum = MonthDays(year, month);
int day = 1;
int w = WeekDay(year, month, day);
MyDate lunarDate;
Lunar(year, month, day, lunarDate);
int nLunarTotalDay = lunarDate.isLeap ? LunarLeapDays(year):LunarMonthDays(year, month);
for (int i=0; i < m_dayNum; ++i)
{
if (lunarDate.day > nLunarTotalDay)
{
Lunar(year, month, day, lunarDate);
nLunarTotalDay = lunarDate.isLeap ? LunarLeapDays(year):LunarMonthDays(year, month);
}
m_day[i].year = m_year;
m_day[i].month = m_month;
m_day[i].day = day++;
m_day[i].week = w++;
m_day[i].lunarY = lunarDate.year;
m_day[i].lunarM = lunarDate.month;
m_day[i].lunarD = lunarDate.day++;
m_day[i].isLeapM= lunarDate.isLeap;
if (w == 7) w = 0;
}
}
// 公历的 y 年 m 月 d 日 是否为农历节气,如果是,则返回 0 - 23。否则返回 -1。
// m 取值 1 - 12
// d 取值 1 - 31
int CCalendar::IsTerm(int y, int m, int d, Term & term)
{
if (y<g_baseY || y>=g_maxY)
return -1;
int s = (m-1)*2;
if (g_term[y-g_baseY][s].day == d) {
term = g_term[y-g_baseY][s];
return s;
}
else if (g_term[y-g_baseY][s+1].day == d) {
term = g_term[y-g_baseY][s+1];
return s+1;
}
return -1;
}
// 取 y 年的 第 n+1 个节气
// n 取值:0 - 23
int CCalendar::GetTerm(int y, int n, Term & term)
{
if (y<g_baseY || y>=g_maxY)
return -1;
term = g_term[y-g_baseY][n];
return 0;
}
// 月纪的起算时间
// 一月 寅月 二月 卯月 三月 辰月 四月 巳月 五月 午月 六月 未月
// 从立春到惊蛰 从惊蛰到清明 从清明到立夏 从立夏到芒种 从芒种到小暑 从小暑到立秋
//
// 七月 申月 八月 酉月 九月 戌月 十月 亥月 十一月 子月 十二月 丑月
// 从立秋到白露 从白露到寒露 从寒露到立冬 从立冬到大雪 从大雪到小寒 从小寒到立春
// 公历的 y 年 m 月 d 日 以时令法 划分的 干支月
int CCalendar::GetTermMonth(int y, int m, int d)
{
if (y<g_baseY || y>=g_maxY)
return -1;
int nTermMonth = (m==1) ? 12 : m-1;
int s = (m-1)*2;
if (d < g_term[y-g_baseY][s].day) {
-- nTermMonth;
if (nTermMonth == 0)
nTermMonth = 12;
}
return nTermMonth;
}
// 生成时令法的干支年月
int CCalendar::GenTermGanzhi(LunarSolarDate & ld)
{
int nTermMonth = GetTermMonth(ld.year, ld.month, ld.day);
// 节气在农历月首之后
if (ld.lunarM == 1 && nTermMonth == 12)
{
ld.cycTermM = ld.monCyl - 1;
ld.cycTermY = ld.lunarY - 1;
}
else if (ld.lunarM - nTermMonth == 1)
{
ld.cycTermM = ld.monCyl - 1;
ld.cycTermY = ld.lunarY;
}
else if (ld.lunarM == 12 && nTermMonth == 1)
{
ld.cycTermM = ld.monCyl + 1;
ld.cycTermY = ld.lunarY + 1;
}
else if (nTermMonth - ld.lunarM == 1)
{
ld.cycTermM = ld.monCyl + 1;
}
else
{
ld.cycTermM = ld.monCyl;
ld.cycTermY = ld.lunarY;
}
return 0;
}
int CCalendar::GenTermGanzhi(int y, int m, int d, int &cycY, int &cycM)
{
MyDate lunarDate;
Lunar(y, m, d, lunarDate);
LunarSolarDate ld;
ld.year = y;
ld.month = m;
ld.day = d;
ld.lunarY = lunarDate.year;
ld.lunarM = lunarDate.month;
ld.lunarD = lunarDate.day;
ld.isLeapM = lunarDate.isLeap;
ld.monCyl = lunarDate.monCyl;
ld.dayCyl = lunarDate.dayCyl;
GenTermGanzhi(ld);
cycY = ld.cycTermY;
cycM = ld.cycTermM;
return 0;
}
void CCalendar::OutPut()
{
int i;
printf("--------------------------------------------------------/n");
printf("%22d 年 %d 月/n", m_year, m_month);
printf(" 周日 周一 周二 周三 周四 周五 周六/n/n");
// 对齐1号的星期
for(i = 0; i < m_day[0].week; ++i)
{
printf(" ");
}
Term term;
int idx;
for(i = 0; i < m_dayNum; ++i)
{
printf("%4d", m_day[i].day);
idx = IsTerm(m_year, m_month, m_day[i].day, term);
if (idx != -1) // 如果是 二十四节气之一,则显示节气
printf("%s", solarTerm[idx]);
else
printf("%s", LunarDay(m_day[i].lunarD).c_str());
if (m_day[i].week == 6) printf("/n/n");
}
printf("/n");
char GanZhi[5];
for (i = 1; i < 10; ++i)
{
MyDate d1;
Lunar(m_year, 2, i, d1);
printf("公历%d年%d月%d日对应的干支(首尾法)", m_year, 2, i);
Cyclical(d1.year-1864, GanZhi);
printf("%s年 ", GanZhi);
Cyclical(d1.monCyl, GanZhi);
printf("%s月 ", GanZhi);
Cyclical(d1.dayCyl, GanZhi);
printf("%s日", GanZhi);
printf(" 时令法:");
int yearCyc, monCyc;
GenTermGanzhi(m_year, 2, i, yearCyc, monCyc);
Cyclical(yearCyc-1864, GanZhi);
printf("%s年 ", GanZhi);
Cyclical(monCyc, GanZhi);
printf("%s月/n", GanZhi);
}
}
// 根据输入的公历年号和月份,返回该月的天数
int MonthDays(int year, int month)
{
if(month==2)
return isleap(year)? 29: 28;
else
return g_solarMonth[month-1];
}
// 根据输入的公历日期,返回对应的星期
int WeekDay(int year, int month, int day)
{
// 万年历的公式:S=X-1+(X-1)/4-(X-1)/100+(X-1)/400+C
// 说明:X为公元年数;
// C为从元旦起,到要算的那天总天数(如:2003年2月13日,C=31+13=44)
// S/7余数为星期几(如余数为0,1,2,3,4,5,6。分别为星期天,星期一,二,
// 三,四,五,六)
long sum = year-1 + (year-1)/4 - (year-1)/100 + (year-1)/400;
for(int i=1; i<month; i++)
sum += MonthDays(year, i);
sum += day;
return (int)sum%7;
}
//------------------------------------------------------------------------------
// 传回农历 y年的总天数
long LunarYearDays(long y)
{
long i, sum = 348; // 29 * 12
for(i=0x8000; i>0x8; i>>=1)
sum += (lunarInfo[y-baseYear] & i)? 1: 0 ;
return(sum+LunarLeapDays(y));
}
// 传回农历 y年闰月的天数
long LunarLeapDays(long y)
{
if(LunarLeapMonth(y))
return((lunarInfo[y-baseYear] & 0x10000)? 30: 29);
else
return(0);
}
// 传回农历 y年闰哪个月 1-12 , 没闰传回 0
long LunarLeapMonth(long y)
{
return(lunarInfo[y-baseYear] & 0xf);
}
// 传回农历 y年m月的总天数
long LunarMonthDays(long y, long m)
{
return( (lunarInfo[y-baseYear] & (0x10000>>m))? 30: 29 );
}
// 传入 offset 传回干支, 0=甲子
void Cyclical(long offset, char GanZhi[5]) {
long i = offset % 60;
if (i < 0)
i += 60;
strcpy(GanZhi, Gan[i%10]);
strcat(GanZhi, Zhi[i%12]);
}
// 根据公历年月日,返回农历信息 dateOut
void Lunar(int year, int month, int day, MyDate & dateOut)
{
int i;
int run=0, ping=0; // 闰年和平年个数
long temp;
long sum;
// 公历1900.1.31为农历的 乙亥年 戊寅月 甲辰日 正月初一
dateOut.monCyl = 14; // 戊寅月
dateOut.dayCyl = 40; // 甲辰日
if ( year>1900 || year==1900 && (month>1 || day==31) )
{
// 计算当前时间 和 1900.1.31 之间的天数差
for(i=1900; i<year; i++)
{
if(isleap(i))
run++;
else
ping++;
}
// 计算总天数
sum = 366*run + 365*ping;
for(i=1; i<month; i++)
sum += MonthDays(year, i);
sum += day;
sum -= 31;
dateOut.dayCyl += sum;
for(i=1900; i<TotalYear && sum>0; i++)
{
temp = LunarYearDays(i);
sum -= temp;
dateOut.monCyl += 12;
}
if(sum<0)
{
sum += temp;
i--;
dateOut.monCyl -= 12;
}
dateOut.year = i;
}
else // 1900.1.31日之前的公历日期
{
// 计算当前时间 和 1900.1.31 之间的天数差
if (year==1900) {
sum = 31-day;
}
else
{
for(i=1899; i>year; --i)
{
if(isleap(i))
run++;
else
ping++;
}
// 计算总天数
sum = 366*run + 365*ping;
for(i=month+1; i<13; ++i)
sum += MonthDays(year, i);
sum += MonthDays(year, month) - day;
sum +=31;
}
dateOut.dayCyl -= sum;
for(i=1899; i>=baseYear && sum>0; i--) {
sum -= LunarYearDays(i);
dateOut.monCyl -= 12;
}
if (sum<0) // 此处,如果sum 大于 0, 则出错,超出农历年的范围
sum = -sum;
dateOut.year = i+1;
}
int leap = LunarLeapMonth(dateOut.year); // 闰哪个月
for (i=1; i<13; ++i)
{
temp = LunarMonthDays(dateOut.year, i);
if (sum >= temp)
sum -= temp;
else
{
dateOut.month = i;
dateOut.day = sum + 1;
dateOut.isLeap = false;
break;
}
if (i == leap) // 闰月
{
temp = LunarLeapDays(dateOut.year);
if (sum >= temp)
sum -= temp;
else
{
dateOut.month = i;
dateOut.day = sum + 1;
dateOut.isLeap = true;
break;
}
}
dateOut.monCyl ++;
}
}
// 返回农历日day的汉子表示, day 取值返回 1-30
string LunarDay(char day)
{
string s;
s.resize(4);
static char nStr1[][3] = {"日","一","二","三","四","五","六","七","八","九","十"};
static char nStr2[][3] = {"初","十","廿","卅"};
switch (day) {
case 10:
s = "初十"; break;
case 20:
s = "二十"; break;
break;
case 30:
s = "三十"; break;
break;
default :
s = nStr2[(int)floor(day/10)];
s+= nStr1[day%10];
}
return(s);
}
cal
最新推荐文章于 2023-11-09 16:30:27 发布