实现日期到农历五行八字转换

这个程序是根据一个C版的公历转农历的程序改的,当初改成了VB版的,昨天被我翻出来又改成了伪C++版,因为时间久了,又是几经“转译”,程序未必完美,权当娱乐吧

#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
	//
	///初始化数据
	//天干表
	const char TianGan[10][3] = {"甲", "乙", "丙", "丁", "戊" , "己", "庚", "辛", "壬", "癸"};
	//地支表
	const char DiZhi[12][3] = {"子", "丑", "寅", "卯", "辰", "巳" , "午", "未", "申", "酉", "戌", "亥"};
	const char ShuXiang[12][3] = {"鼠", "牛", "虎", "兔", "龙", "蛇" , "马", "羊", "猴", "鸡", "狗", "猪"};
	const char DayName[30][5] = {"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八" , "初九", "初十",
								"十一", "十二", "十三", "十四", "十五", "十六" , "十七", "十八", "十九", "二十",
								"廿一", "廿二", "廿三", "廿四" , "廿五", "廿六", "廿七", "廿八", "廿九", "三十"};
	const char MonName[12][5] = {"正", "二", "三", "四", "五", "六" , "七", "八", "九", "十", "十一", "腊"};
	const char WuXing[5][3] = {"木", "火", "土", "金", "水"};
	//地支对应的五行表,规律怪,与其计算,还不如查表快
	const char wuxing[12][3] = {"水", "土", "木", "木", "土", "火" , "火", "土", "金", "金", "土", "水"};
	/*
	const int NongliData[100]的数据构成:
	低16位表示(12个或13个月)每个月是大月还是小月,高16位表示闰哪个月
	比如2006年表中10进制464219,16进制0x7155b,
	二进制
	0000 0000 0000 0111 0001 0101 0101 1011
	|--------闰7月------|-------98 *765 4321---|
	(*闰月,这里闰7月) 比如2007年表中10进制605,16进制0x25D,
	二进制
	0000 0000 0000 0000 0000 0010 0101 1011
	|--------无闰月-----|--------9 8765 4321---|
	*/
	const int NongliData[100] = {
							2635,333387,1701,1748,267701,694,2391,133423,1175,396438,
							3402,3749,331177,1453,694,201326,2350,465197,3221,3402,
							400202,2901,1386,267611,605,2349,137515,2709,464533,1738,
							2901,330421,1242,2651,199255,1323,529706,3733,1706,398762,
							2741,1206,267438,2647,1318,204070,3477,461653,1386,2413,
							330077,1197,2637,268877,3365,531109,2900,2922,398042,2395,
							1179,267415,2635,661067,1701,1748,398772,2742,2391,330031,
							1175,1611,200010,3749,527717,1452,2742,332397,2350,3222,
							268949,3402,3493,133973,1386,464219,605,2349,334123,2709,
							2890,267946,2773,592565,1210,2651,395863,1323,2707,265877};
	//const int MonthAdd[12]是当前月之前的经过的整月天数,二月暂以28天计
	const int MonthDay[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
	//平年和闰年的月表
	const int _Month[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},
							{31,29,31,30,31,30,31,31,30,31,30,31}};
	//
	//
	///输入日期
	int year, month, day, hour;
	cout << "请输入要查询者的相关内容/n" << endl;
	while (cout << "请输入 年份(1922 - 2021):" && cin >> year)
		if(year >= 1922 && year <= 2021)
			break;
	//闰年计算,其实这里可以不用这么精确的计算,直接year % 4 == 0即可,因为年份跨度不大
	int leapyear = (year % 4 == 0) && ((year % 100 != 0)||(year % 400 == 0)) ? 1 : 0;
	while (cout << "请输入 月份(1 - 12):" && cin >> month)
		if(month >= 1 && month <= 12)
			break;
	while (cout << "请输入 日期(1 - 31):" && cin >> day)
		if(day >= 1 && day <= _Month[leapyear][month - 1])
			break;
	while (cout << "请输入 时刻(0 - 23):" && cin >> hour)
		if(hour >= 0 && hour <= 23)
			break;
	cout << "/n" << year << " - " << month << " - " << day << " - " << hour << endl;
	//
	//
	///预转换
	hour = (++hour) >= 24 ? 0 : hour / 2;
	//时间转换成时辰
	//计算日期差 X<-TheDate->1921-2-8
	//1921-2-8(辛酉年庚寅月壬寅日)而1921-1-1(辛酉年戊子月甲子)
	int sDay = (year - 1921) * 365 + (year - 1921) / 4 + day + MonthDay[month - 1] - 38;//38是代表是从1921-2-8(正月初一)开始计算,而不是1921-1-1,去除38天
	//如今年阳历是闰年(2月有29天),而且当前月份大于2月,经历的总天数加1
	if((!(year % 4)) && (month > 2)) sDay = sDay + 1;
	//
	//
	///农历数据转换
	bool IsEnd = false;
	int mYear = 0, h = 0, TDMonth = 0, TheDate = sDay, mMonth, n;
	//逐年逐月减天数
	while(!IsEnd) {
		if(NongliData[mYear] < 4095) {//判断是否有闰月
			mMonth = 11;
		}
		else {
			mMonth = 12; //有闰月,故一年有13个月
			++h;
		}
		n = mMonth;
		while(n >= 0) {
			int Bit = NongliData[mYear];
			Bit = (Bit >> n) & 1;
			//大小月补差
			if (TheDate <= (29 + Bit)) {//判断天数是否少于当月实际总天数
				IsEnd = true; break;
			}
			++TDMonth; //农历月份累加
			TheDate -= 29 + Bit; --n;
		}
		if(IsEnd)
			break;
		++mYear; //农历年份累加
	}
	month = mMonth - n;
	TDMonth = TDMonth - h;
	day = TheDate;
	if (mMonth == 12) {//判断闰月及相关数据调整
		if (month < NongliData[mYear] / 65536)
			++TDMonth;
		else if (month == NongliData[mYear] / 65536) //正好是闰月
			month = 1 - month;
		else if (month > NongliData[mYear] / 65536) //如果为闰月后面的月份,月份值调整
			--month;
	}
	int Tian[4], Di[4];
	///各天干计算:年、月、日、时
	Tian[0] = (mYear + 7) % 10;
	Tian[1] = (TDMonth + 6) % 10;
	Tian[2] = (sDay + 7) % 10;
	Tian[3] = ((Tian[2] % 5) * 2 + hour) % 10;
	///各地支计算:年、月、日、时
	Di[0] = (mYear + 9) % 12;
	Di[1] = (TDMonth + 2) % 12;
	Di[2] = (sDay + 1) % 12;
	Di[3] = hour;
	const char *theWuXing[8];
	///天干地支对应的五行属性
	//年
	theWuXing[0] = WuXing[Tian[0] / 2];
	theWuXing[1] = wuxing[Di[0]];
	//月
	theWuXing[2] = WuXing[Tian[1] / 2];
	theWuXing[3] = wuxing[Di[1]];
	//日
	theWuXing[4] = WuXing[Tian[2] / 2];
	theWuXing[5] = wuxing[Di[2]];
	//时
	theWuXing[6] = WuXing[Tian[3] / 2];
	theWuXing[7] = wuxing[Di[3]];
	//五行统计
	bool nWuXing[5] = {true, true, true, true, true};
	for(int i = 0; i != 8; ++i)
		for(int n = 0; n != 5; ++n)
			if(0 == strcmp(theWuXing[i], WuXing[n] ))
				nWuXing[n] = false;

	char NongliStr[7];
	sprintf(NongliStr, "%s%s年", TianGan[Tian[0]], DiZhi[Di[0]]);//显示XX年
	char NongliDayStr[13];
	//显示(闰)X月
	if (month < 0) //判断是否为闰月
		sprintf(NongliDayStr, "闰%s月", MonName[-1 * month]);
	else
		sprintf(NongliDayStr, "%s月", MonName[month]);
	strcat(NongliDayStr, DayName[day - 1]);
	//
	//
	///结果输出
	cout << "\n农历:" << NongliStr << "(" << ShuXiang[(mYear + 9) % 12] << ") " << NongliDayStr << " " << DiZhi[Di[3]]
	<< "时\n" << NongliStr << " " << TianGan[Tian[1]] << DiZhi[Di[1]] << "月 " << TianGan[Tian[2]] << DiZhi[Di[2]]
	<< "日 " << TianGan[Tian[3]] << DiZhi[Di[3]] << "时" << "\n\n八字为:"
	<< TianGan[Tian[0]] << DiZhi[Di[0]] << TianGan[Tian[1]] << DiZhi[Di[1]] << TianGan[Tian[2]] << DiZhi[Di[2]]
	<< TianGan[Tian[3]] << DiZhi[Di[3]] << "\n五行为:" << theWuXing[0] << theWuXing[1] << theWuXing[2] << theWuXing[3]
	<< theWuXing[4] << theWuXing[5] << theWuXing[6] << theWuXing[7] << endl;

	cout << "五行缺:\t";
	for(int i = 0; i != 5; ++i)
		if(nWuXing[i])
			cout << WuXing[i];
	cout << endl;
	//
	//
	return 0;
}

中国的农历是相当博大精深的,此处仅以数据表的方式来查询农历闰月及大小月。同时,这个程序是以正月初一,作为新一年的分界。实际上也有以春分作为新一年的分界的。

P.S 代码显示效果不好,下次改用工具编辑好了再上传

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值