一个农历软件,求测试。

由本社区发起的开源项目
回复
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

一个农历软件,求测试。

#1

帖子 YeLee » 2013-09-07 18:27

最近在一个网站找的一个查农历的代码,听作者介绍说信息是来自香港天文台的。

代码: 全选

//table.h
#define YEAR_SRT 1901
#define YEAR_NUM 200
#define THIS_YEAR(x) Year_Info[x - YEAR_SRT]

static long Year_Info[YEAR_NUM] = {
/*
	YEAR:LC:ZY:ZYDAY:L:LEAP:MONTHS
	1901:01:10:10011:0:0000:010010101111
	年   立 春 春    闰闰无 十非的
	份   春 节 节    月月则 二闰大
             日 阳 阳    大月为 个月小
             偏 历 历    小份零
             移 月 日
             量 份 期
*/
0x1A604AF, 0x2900A57, 0x27A554D, 0x2A00D27, 0x1880D95, //1901-1905
0x2734655, 0x29A056B, 0x28409AD, 0x16C255D, 0x29404AF, //1906-1910
0x27C6A5B, 0x2A40A4D, 0x18C0D25, 0x1755D25, 0x29C0B55, //1911-1915
0x2860D6A, 0x16E2ADA, 0x196095B, 0x2837497, 0x2A80497, //1916-1920
0x1900A4B, 0x1785B4B, 0x2A006A5, 0x28A06D5, 0x1714AB5, //1921-1925
0x19A02B7, 0x2840957, 0x26E252F, 0x1940497, 0x17C6656, //1926-1930
0x2A20D4A, 0x28C0EA5, 0x17556A9, 0x19C05AD, 0x28802B7, //1931-1935
0x271386E, 0x196092E, 0x17F7C8D, 0x2A60C95, 0x2900D4B, //1936-1940
0x1776D8A, 0x19E0B55, 0x28A056B, 0x2734A5B, 0x19A025D, //1941-1945
0x184092D, 0x16C2D2B, 0x2940A95, 0x17A7B55, 0x1A206CB, //1946-1950
0x18C0B55, 0x2775535, 0x19C04DB, 0x1860A5B, 0x1713457, //1951-1955
0x298052B, 0x17E8A9B, 0x1A40E95, 0x19006AB, 0x2786AEA, //1956-1960
0x19E0AB5, 0x18A04B7, 0x1724AAE, 0x29A0A57, 0x1840527, //1961-1965
0x16A3F26, 0x1920D95, 0x27C75B5, 0x1A2056B, 0x18C096D, //1966-1970
0x17654DD, 0x29E04AD, 0x1860A4D, 0x16E4D4D, 0x1960D25, //1971-1975
0x27E8D55, 0x1A40B55, 0x18E0B6A, 0x179695A, 0x2A0095B, //1976-1980
0x18A049B, 0x1724A97, 0x19A0A4B, 0x184AB27, 0x1A806A5, //1981-1985
0x19206D5, 0x17A6AF4, 0x1A20AB6, 0x18C0957, 0x17654AF, //1986-1990
0x19E0497, 0x188064B, 0x16E374A, 0x1940EA5, 0x17E86B5, //1991-1995
0x1A605AD, 0x18E0AB6, 0x178596D, 0x1A0092F, 0x18A0C96, //1996-2000
0x1704D95, 0x1980D4B, 0x1820DA5, 0x16C2755, 0x192056B, //2001-2005
0x17A7ABB, 0x1A4025D, 0x18E092D, 0x1745CAB, 0x19C0A95, //2006-2010
0x1860B4B, 0x16E4BAA, 0x1940AD5, 0x17E955D, 0x1A604BB, //2011-2015
0x1900A5B, 0x0796517, 0x1A0052B, 0x18A0A93, 0x1724795, //2016-2020
0x09806AB, 0x1820AD5, 0x16C25B5, 0x19404B7, 0x07A6A6E, //2021-2025
0x1A20A4E, 0x18C0D26, 0x1745EA6, 0x09A0D53, 0x18605AB, //2026-2030
0x16E376A, 0x196096D, 0x07EB4AF, 0x1A604AD, 0x1900A4D, //2031-2035
0x1796D0B, 0x09E0D25, 0x1880D53, 0x0705BD4, 0x1980B5A, //2036-2040
0x082056D, 0x16C255B, 0x194049B, 0x17C7A57, 0x0A20A4B, //2041-2045
0x18C0AA5, 0x1755B25, 0x19C06D3, 0x0840ADA, 0x06F34B6, //2046-2050
0x1960937, 0x182849F, 0x0A60497, 0x090064B, 0x179668A, //2051-2055
0x19E0EA5, 0x08806AB, 0x0714A6C, 0x0980AAE, 0x184092E, //2056-2060
0x06A3D2E, 0x0920C96, 0x17A7D55, 0x1A20D4B, 0x08A0DA5, //2061-2065
0x07455D5, 0x19C056B, 0x1860A6D, 0x06E455D, 0x096052D, //2066-2070
0x17E8A9B, 0x1A60A95, 0x08E0B4B, 0x0766B6A, 0x19E0AD5, //2071-2075
0x18A055B, 0x0704ABA, 0x0980A5B, 0x184052B, 0x16C3B27, //2076-2080
0x0920693, 0x07A7733, 0x0A206AB, 0x18C0AD5, 0x07554B5, //2081-2085
0x09C04B7, 0x0860A57, 0x170454E, 0x0940D16, 0x07C8E96, //2086-2090
0x0A40D52, 0x18E0DAA, 0x07766AA, 0x09E056D, 0x08A04AF, //2091-2095
0x1724A9D, 0x0980A2D, 0x0820D15, 0x06A2F25, 0x1920D53  //2096-2100
};

[/c]
[c]
//lunar.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "table.h"

#ifndef uint
typedef unsigned int uint;
#endif

uint dayofspring(const uint year)
{
	if (((THIS_YEAR(year) & 0xC00000) >> 22) == 1)
		return ((THIS_YEAR(year) & 0x3E0000) >> 17) - 1;
	return ((THIS_YEAR(year) & 0x3E0000) >> 17) - 1 + 31;
}

uint dayofyear(const uint year, const uint mon, const uint mday)
{
	static int monofday[12] = {0, 31, 59, 90, 120, 151,
		181, 212, 243, 273, 304, 334}; 
	uint day = 0;
	day = monofday[mon - 1] + mday - 1;
	if ((mon > 2) &&
			((((year % 4) == 0) && ((year % 100) != 0)) ||
			((year % 400) == 0)))
		day++;
	return day;
}

uint dayoffset(const uint year, const uint mon, const uint mday)
{
	uint yday = dayofyear(year, mon, mday);
	uint dspr = dayofspring(year);

	if (yday >= dspr) return (yday - dspr);

	uint last = dayoffset(year - 1, 12, 31);
	if (mon == 1) return (last + mday);
	return (last + 31 + mday);
}

uint monday(const uint year, const uint dayoffset)
{
	uint months = 12;
	uint monday = 0;
	uint leap = ((THIS_YEAR(year) & 0xF000) >> 12);
	uint nleap = ((THIS_YEAR(year) & 0x10000) >> 16);
	uint lmon = 0x1000;

	if (leap) {
		months = 13;
		monday |= (leap << 9);
		monday |= (nleap << 13);
	}

	uint i = 0;
	uint left = dayoffset;

	for (i = 1; i <= months ; i++)
	{
		uint mdays = 0;
		if (!leap || (i != (leap + 1))) {
			mdays = ((lmon >> i) & THIS_YEAR(year))? 30 : 29;
		} else {
			i--;
			leap = 0;
			months = 12;
			mdays = (nleap? 30 : 29);
			if (left < mdays) i = 0;
		}
		if (left < mdays) {
			monday |= (i << 5);
			monday |= left;
			return monday;
		}
		left -= mdays;
	}

	return 0;
}

uint getrealmonday(const uint year, const uint mon, const uint mday)
{
	if (dayofyear(year, mon, mday) >= dayofspring(year)) {
		return (monday(year, dayoffset(year, mon, mday)));
	}
	return (monday(year - 1, dayoffset(year, mon, mday)));
}

void ganzhi(const uint year, const uint mon, const uint mday)
{
	static char* tgGB[] = { "甲", "乙", "丙", "丁", "戊",
		"己", "庚", "辛", "壬", "癸" };
	static char* dzGB[] = { "子", "丑", "寅", "卯", "辰",
		"巳", "午", "未", "申", "酉", "戌", "亥" };

	uint i = 6, j = 8;
	uint realyear = year;
	uint lcoffset = ((0x3000000 & THIS_YEAR(year)) >> 24);

	//懒得算立春日了 -_-||
	if (dayofyear(year, mon, mday) < (31 + 2 + lcoffset)) 
		realyear -= 1;

	uint noun = realyear % 60;
	i += noun;
	i %= 10;
	j += noun;
	j %= 12;
	printf("%s%s年", tgGB[i], dzGB[j]);
}

void printmonday(uint monday)
{
	static char* numGB[] = { "初一", "初二", "初三", "初四", "初五",
		"初六", "初七", "初八", "初九", "初十",
		"十一", "十二", "十三", "十四", "十五",
		"十六", "十七", "十八", "十九", "二十",
		"廿一", "廿二", "廿三", "廿四", "廿五",
		"廿六", "廿七", "廿八", "廿九", "三十" };
	static char* monGB[] = { "正月", "二月", "三月", "四月", "五月",
		"六月", "七月", "八月", "九月", "十月", "冬月", "腊月" };
	uint mon = ((monday >> 5) & 0xF);
	uint mday = (monday & 0x1F);

	if (!mon) {
		printf("闰%s%s\n", monGB[((monday >> 9) & 0xF) - 1], numGB[mday]);
	} else {
		printf("%s%s\n", monGB[mon - 1], numGB[mday]);
	}
}

void usage(char* argv)
{
	fprintf(stderr, "%s [%d-%d] [1-12] [1-31]\n", argv,
			YEAR_SRT, YEAR_SRT + YEAR_NUM - 1);
	return;
}

int isdate(const uint year, const uint mon, const uint mday)
{
	if (mon > 12) return 0;
	if (mon == 2) {
		if ((((year % 4) ==  0) && ((year % 100) != 0)) ||
			((year % 400) == 0)) {
			if (mday > 29) return 0;
			return 1;
		}
		if (mday > 28) return 0;
		return 1;
	}
	if ((mon == 1) || (mon == 3) || (mon == 5) || (mon == 7) || (mon == 8) ||
			(mon == 10) || (mon == 12)) {
		if (mday > 31) return 0;
		return 1;
	}
	if ((mon == 2) || (mon == 4) || (mon == 6) || (mon == 9) || (mon == 11)) {
		if (mday > 30) return 0;
		return 1;
	}
	return 0;
}

int main(int argc, char* argv[])
{
	if ((argc != 1) && (argc != 4)) {
		usage(argv[0]);
		return 1;
	}
	uint year = 0, mon = 0, mday = 0;

	int i = 1, j =0;
	if (argc == 4) {
		for (i = 1; i < 4; i++) {
			for (j = 0; j < strlen(argv[i]); j++) {
					if (!isdigit(* (argv[i] + j))) {
						usage(argv[0]);
						return 1;
					}
			}
		}
		year = atoi(argv[1]);
		mon = atoi(argv[2]);
		mday = atoi(argv[3]);
		if (!isdate(year, mon, mday)) {
			usage(argv[0]);
			return 1;
		}
	}

	if(argc == 1) {
		time_t cur_t = 0;
		time(&cur_t);
		struct tm* cur_tm = NULL;
		cur_tm = localtime(&cur_t);
		year = (cur_tm->tm_year) + 1900;
		mon = (cur_tm->tm_mon) + 1;
		mday = cur_tm->tm_mday;
	}

	if ((year < YEAR_SRT) || (year > (YEAR_SRT + YEAR_NUM - 1))) {
		usage(argv[0]);
		return 1;
	}

	if ((year == YEAR_SRT) &&
			(dayofyear(year, mon, mday) < dayofspring(year))) {
		usage(argv[0]);
		return 1;
	}

	ganzhi(year, mon, mday);
	uint monday = getrealmonday(year, mon, mday);
	if (monday) printmonday(monday);

	return 0;
}

由于鄙人不会C语言,不过想了解一下是怎么实现的,所以想求各位大大解释一下这些代码的意思,先谢谢了。 :em02
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
onlylove
论坛版主
帖子: 4436
注册时间: 2007-01-14 16:23
送出感谢: 0
接收感谢: 100 次

Re: 一个农历软件,求测试。

#2

帖子 onlylove » 2013-09-07 18:31

不懂C没啥,这个其实就是根据农历的推算方法(叫历法比较准确点?)来写的,说白了就是和计算机讲农历怎么计算,就像数学里面让你算闰年似的(算闰年的算法比农历简单多啦)
这些用户感谢了作者 onlylove 于这个帖子:
YeLee (2013-09-07 18:36)
评价: 3.7%
#include <stdio.h>
void main()
{
double world;
unsigned letter;
short stay;
long memories;
printf("I miss you.\n");
}
onlylove
论坛版主
帖子: 4436
注册时间: 2007-01-14 16:23
送出感谢: 0
接收感谢: 100 次

Re: 一个农历软件,求测试。

#3

帖子 onlylove » 2013-09-07 18:35

不过这个软件……算的是200年的,从1901到2100年的,用法应该是编译以后执行,然后输入年月日(空格分开)

代码: 全选

void usage(char* argv)
{
        fprintf(stderr, "%s [%d-%d] [1-12] [1-31]\n", argv,
                        YEAR_SRT, YEAR_SRT + YEAR_NUM - 1);
        return;
}
然后计算的
#include <stdio.h>
void main()
{
double world;
unsigned letter;
short stay;
long memories;
printf("I miss you.\n");
}
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#4

帖子 YeLee » 2013-09-07 18:41

谢谢onlylove了。 :em05
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
onlylove
论坛版主
帖子: 4436
注册时间: 2007-01-14 16:23
送出感谢: 0
接收感谢: 100 次

Re: 一个农历软件,求测试。

#5

帖子 onlylove » 2013-09-07 18:53

轮子居然点了感谢,吓坏了 :em20
#include <stdio.h>
void main()
{
double world;
unsigned letter;
short stay;
long memories;
printf("I miss you.\n");
}
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#6

帖子 YeLee » 2013-09-12 16:22

有没有人会的?难道这论坛就没有高手了吗? :em20
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
头像
cjxgm
帖子: 1950
注册时间: 2010-04-23 20:40
系统: Arch Linux
来自: 浙江·杭州
送出感谢: 1 次
接收感谢: 30 次
联系:

Re: 一个农历软件,求测试。

#7

帖子 cjxgm » 2013-09-12 20:24

表示解释代码是一种痛苦……

Sent from Android 4.0
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#8

帖子 YeLee » 2013-09-12 23:24

是不是这问题太难了,所以大家都不会啊? :em20
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙
送出感谢: 4 次
接收感谢: 256 次

Re: 一个农历软件,求测试。

#9

帖子 eexpress » 2013-09-13 11:33

算了干嘛,直接网站获取。
另外,用C处理字符串,你在找虐。
● 鸣学
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#10

帖子 YeLee » 2013-09-13 11:52

ee难道不知道c假如加一个libcurl的话,代码量又要拖多长来着……更何况我只是靠程序自己算的,也不用花多少时间采集数据吧。 :em01
另,用C处理字串,我倒不觉得有什么自作孽的,反正之前写过一个字串操作的库,动态分配字串这些东西都直接扔给库处理了。
更重要的一点,不知ee有没有留意,其实这段代码里面压根就没有什么复杂的字串操作之类的,甚至连个动态内存的东西都没有,多的只是位操作。
C的位运算我倒觉得弄起来非常有意思,起码比你们家的perl好多了。 :em05
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
头像
millenniumdark
论坛版主
帖子: 4159
注册时间: 2005-07-02 14:41
系统: Ubuntu 14.04 (Kylin)
送出感谢: 42 次
接收感谢: 9 次
联系:

Re: 一个农历软件,求测试。

#11

帖子 millenniumdark » 2013-09-13 11:59

源里有lunar这个包的。
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#12

帖子 YeLee » 2013-09-13 12:23

之前看过lunar的代码,由于立春日与干支的问题鄙人目前仍混淆不清,故没有采用。 :em01
更何况这东西只是弄给conky看的,要那么多输出干嘛?我还想用一个更舒服的办法来实现。
呵呵,扯远了,反正这年头也不少缺轮子,我这里不过是提供自己的算法而已。 :em01
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
buntutu
帖子: 61
注册时间: 2009-11-25 1:38
送出感谢: 0
接收感谢: 6 次

Re: 一个农历软件,求测试。

#13

帖子 buntutu » 2013-09-18 17:27

主要就是 table.h 里的内容,写的很清楚了,竖着看。

代码: 全选

/*
        YEAR:LC:ZY:ZYDAY:L:LEAP:MONTHS
        1901:01:10:10011:0:0000:010010101111
        年   立 春 春    闰闰无 十非的
        份   春 节 节    月月则 二闰大
             日 阳 阳    大月为 个月小
             偏 历 历    小份零
             移 月 日
             量 份 期
*/
把每年推算信息(春节对应阳历日,润月月分,大小,非润月大小)都放到一个数字里了,用的时候根据年份查表。

知道了春节的阳历日期,就知道了阴历的第一天在哪里。知道了润月是哪几月,大小月,得到每个月的天数,就可以从第一天(春节)推算出相应的阴历月和阴历日。其他都是细节,比如春节前的日子使用前一年的信息,都是常识。所以理解了那个表的意思,自己根据常识就可以推算了,不必懂C。

至于干支,网上查一下,干支历的开始是从立春开始的,不是春节,所以干支年就要考虑那一天是立春前还是立春后,而不是跟春节做比较。他好像没有算干支的月和日。

所以其实不是什么推算,只是算好基本信息,然后查表后做简单推算。
头像
YeLee
论坛版主
帖子: 26386
注册时间: 2008-08-13 8:48
系统: Fundu i64
来自: 东海硇州,一双管钥。
送出感谢: 25 次
接收感谢: 307 次
联系:

Re: 一个农历软件,求测试。

#14

帖子 YeLee » 2015-02-25 12:14

回来一看,发现自己之前居然写过一些这么糟糕的代码啊。 :em01
◎当我站在道德的高度上俯视别人的时候,发现自己是多么渺小。
♥执着但不偏激,反对而不排斥,坚决捍卫矛盾体的存在方式。
★★★天气预报★★★
fcitx-yatable一个可以使用的码表输入法
[教程]几个实例攻克软件编译难关
Gentoo Development Guide
字体相关
回复

回到 “开源小工具”