打印

最精简的公历农历转换程序(C源程序)

[复制链接]
5763|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xukaiguo|  楼主 | 2009-10-8 17:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xukaiguo 于 2009-10-8 17:22 编辑

上一贴的链接必须登录QQ才可以看到,原贴已超时,不能再编辑,因此把原文贴在这里:

此程序为本人所写,免费供有需要的人使用,无版权纠纷;
程序的功能是输入2000年2月5日(正月初一)至2100年12月31日之间的公历日期,输出对应的农历日期(闰月以月份+128表示);
该程序比较精简,适合资源紧张的MCU场合。由IAR编译成MSP430的目标代码,大约占用600个字节的程序空间,如改用汇编,去除多余的头尾,应该可以缩减到500字节以内;

程序特色在于用101个16位字表述了101年的农历大小月及闰月的数据。低12位表示对应12个月的月大或月小,最低位为正月,1表示月大;高4位为0时表示当年及下一年无闰月;高4位为1~12时表示下一年度的相应月存在闰月;高4位为13或14时,分别表示当前年的闰月为月小或月大。按照这个结构可以扩充到更多年份,但程序中对非闰年的公历1900,2200,2300,2500年份未作处理,仅对2100作为特例处理。另外,扩展到更多年份后某些变量可能存在溢出。
为简化程序,在转换函数内对输入日期的合法性未作判别,如输入1810-2-15、2008-6-31、2135-1-1等,将导致不可预料的输出结果。
提醒:程序仅对二三十个比较典型的日期进行了抽样测试,未做逐月验证,对于相近农历月大小颠倒的情况不能排除,如作为产品使用,请再次确认转换表数据的正确性。

//Lunar calendar convert program
//Designed by QQ984809120, 2009-10-6
/*
convert table(2000~2100) structure:
D15~D12=0000  Current and next year no leap month
D15~D12=0001~1100 leap month number of next year
D11~D0 = days of 12 months, 1: 30 days; 0: 29 days
D15~D12=1110  30 days in leap month of current year
D15~D12=1101  29 days in leap month of current year

*/
const unsigned int table[101] = {0x4693,
0xDA9B, 0x052B, 0x2A5B, 0xDAAE, 0x756A, 0xDDD5, 0x0BA4, 0x5B49, 0xDD53, 0x0A95,
0x452D, 0xD55D, 0x9AB5, 0xDBAA, 0x05D2, 0x6DA5, 0xEE8A, 0x0D4A, 0x4C95, 0xDA9E,
0x0556, 0x2AB5, 0xDADA, 0x66D2, 0xD765, 0x0725, 0x564B, 0xD657, 0x0CAB, 0x355A,
0xD56E, 0xBB69, 0xDF52, 0x0B52, 0x5B25, 0xDD2B, 0x0A4B, 0x54AB, 0xD2BB, 0x05AD,
0x2B6A, 0xDDAA, 0x7D92, 0xDEA5, 0x0D25, 0x5A55, 0xEA4D, 0x04B6, 0x35B5, 0xE6D2,
0x8EC9, 0xDF92, 0x0E92, 0x6D26, 0xE516, 0x0A57, 0x44D6, 0xE365, 0x0755, 0x3749,
0xD74B, 0x7693, 0xDAAB, 0x052B, 0x5A5B, 0xDABA, 0x056A, 0x4B65, 0xDBAA, 0x8B4A,
0xDD95, 0x0A95, 0x652D, 0xD56D, 0x0AB5, 0x55AA, 0xE5C5, 0x0DA5, 0x3D4A, 0xDE4D,
0x7C96, 0xDCCE, 0x0556, 0x5AB5, 0xEAD2, 0x06D2, 0x5EA5, 0xD72A, 0x868B, 0xD697,
0x04AB, 0x655B, 0xE556, 0x0B6A, 0x4752, 0xDB95, 0x0B25, 0x2A8B, 0xDA4F, 0x04AB};

/*Convert routine
00<yy<=100, 1<=mm<=12, 1<=dd<=31
*/

date_cvt (unsigned char yy, unsigned char mm, unsigned char dd, unsigned char *buff)

{ unsigned char i,j,leap;
  unsigned int days1,days2,x;

   days1 = yy * 365 + ((yy+3)>>2) + (mm-1)*30 + dd;
   if ((mm >2) && ((yy & 3) == 0) && (yy != 100))
       days1 ++;
   switch(mm)
    {
     case 3:  days1--;
              break;
     case 11:
     case 12: days1 ++;
     case 9:
     case 10: days1 ++;
     case 8:  days1 ++;
     case 2:
     case 6:
     case 7:  days1 ++;
    }   //------days from 1999-12-31

   days1 -=35;
   days2=0;
   leap=0xFF;
   for (i=0; i<=100; i++)
    {x=table;
     for (j=0; j<12; j++)
       {
         days2 += 29 + (x & 1);
         if (days2 >= days1)
           break;
  
         if (j==leap)
         {
         days2 += 16 + (table >> 12);
            if (days2 >= days1)
               {  j |= 0x80;
                  x = ~(table >> 12);
                  break;
                }
         }  
         x >>= 1;
       }

     if (days2 >= days1)
       break;
     
     leap = x-1;
    }

   * buff++ = i;  //output result
   * buff++ = j+1;
   * buff   = (unsigned char) (29 + (x & 1) -(days2-days1));
}

main()   /*main program*/
{ unsigned char buff[3]; //Save year(xx:20xx),month,day
  date_cvt( 9, 10, 6, &buff[0]);  //Only for example
}

相关帖子

沙发
duojinian| | 2009-10-9 08:05 | 只看该作者
thanks

使用特权

评论回复
板凳
LZL_83| | 2009-10-25 15:39 | 只看该作者
收藏,谢谢

使用特权

评论回复
地板
lixiaopeng| | 2009-10-25 22:55 | 只看该作者
谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

52

帖子

0

粉丝