农历日期转换库中数组数字的含义与来源技术咨询
中国农历转换库中lunarInfo数组的数字含义解析
我正在开发一款涵盖多国节假日的应用,为获取中国节假日日期需实现公历与农历的转换。找到的多款农历转换库,均采用了一个lunarInfo数组,数组中每个元素对应一个农历年的编码信息,示例如下:
final static long[] lunarInfo = new long[] { 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0 };
这些编码是二进制位掩码,每一位对应农历年的特定属性,具体含义如下:
编码位含义
每个十六进制数可拆解为17位二进制位,各段功能划分:
- 第17位(对应十六进制
0x10000):标记闰月天数,1表示闰月为30天(大闰月),0表示闰月为29天(小闰月) - 第16-13位(对应十六进制
0xF000):存储闰月月份,取值0-12,0代表当年无闰月,1-12依次对应闰正月到闰腊月 - 第12-1位(对应十六进制
0xFFF):共12位,依次对应农历正月到腊月,每一位为1表示该月是30天的大月,0表示29天的小月
结合示例代码解析
农历年总天数计算(yearDays方法)
final private static int yearDays(int y) { int i, sum = 348; for (i = 0x8000; i > 0x8; i >>= 1) { if ((lunarInfo[y - 1900] & i) != 0) sum += 1; } return (sum + leapDays(y)); }
- 初始值
sum=348是12个小月的总天数(12×29=348) - 循环遍历第16到第4位(共12位),对应农历12个月份的大小标记:每遇到位值为1(大月),就给sum加1(大月比小月多1天)
- 最后加上闰月的天数(如果存在),得到该农历年的总天数
闰月天数计算(leapDays方法)
final private static int leapDays(int y) { if (leapMonth(y) != 0) { if ((lunarInfo[y - 1900] & 0x10000) != 0) return 30; else return 29; } else return 0; }
- 先通过
leapMonth(y)读取编码中的闰月月份位,判断当年是否有闰月 - 若有闰月,检查第17位的值:为1则返回30天,否则返回29天;无闰月则返回0
编码数据的来源
这些数组中的编码是基于中国农历的天文观测与计算结果预生成的历表数据。农历是阴阳合历,需要协调太阳回归年与朔望月的周期,因此每年的月份大小、闰月安排都需要通过天文计算确定。这类数组通常提前计算好某一时间段(比如1900年至2100年)的农历信息,供转换库直接使用。
内容的提问来源于stack exchange,提问作者Emmanuel BRUNO
相关产品推荐
相关产品推荐

