找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6250|回复: 6
收起左侧

51单片机阳历转农历(仅仅是阳历转阴历例程)

  [复制链接]
ID:310680 发表于 2018-12-30 22:31 | 显示全部楼层 |阅读模式
之前要做一个万年历,从论坛上辗转多处,最终发现以下这个阳历转换阴历的程序比较简单,数据带入可以直接使用,不过测试发现转换有问题,后面进行仿真调试找到问题所在,从而进而修改。不知道是我复制出错,还是自己不经意间修改才导致问题出现,已经修复,需要阳历转阴历的可以拿去。找不到具体来源,因此无法标志引用链接地址,如有侵权,联系删除。
问题所在:在SPDATE GetSpringDay(uchar GreYear,uchar GreMon,uchar GreDay)函数里面的参数定义,把Offset1定义为uchar类型,后面计算时Offset1数值溢出,将uchar改为uint后,数据不在溢出,进行上机测试,转换成功。
  1. //公曆轉農曆(1901-2100)
  2. //亦木明 2008.1.11
  3. //2018.12.30清枫城主测试,发现存在问题,通过仿真一步步走找出问题所在,并作出修正
  4. //原文在哪忘了,只知道作者有“亦木明”的标注,如有侵权联系删除
  5. #include "12c5a60s2.h"//可修改为51的头文件   


  6. #define TRUE  1
  7. //公历年对应的农历数据,每年三字节,
  8. //格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
  9. //第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
  10. //月份对应的位为1 表示本农历月大(30 天),为0 表示小(29 天).
  11. //第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期
  12. //每年的數據對應在數組中的位置庫 (200-(2100-year)-1)*3+Offset1  
  13. //0x09,0x2d,0x47, //2008  0x47 01000111
  14. //0x4d,0x4A,0xB8, //2001

  15. typedef struct spdate
  16. {
  17.         char         cYear;
  18.         char        cMon;
  19.         char        cDay;
  20. }SPDATE;


  21. uchar code Data[]={

  22. 0x04,0xAe,0x53, //1901  0        (200-(2100-1901)-1)*3=0
  23. 0x0A,0x57,0x48, //1902        3   (200-(2100-1902)-1)*3=3
  24. 0x55,0x26,0xBd, //1903        6        (200-(2100-1903)-1)*3=3
  25. 0x0d,0x26,0x50, //1904        9   (200-(2100-year)-1)*3
  26. 0x0d,0x95,0x44, //1905        12        
  27. 0x46,0xAA,0xB9, //1906        15
  28. 0x05,0x6A,0x4d, //1907
  29. 0x09,0xAd,0x42, //1908
  30. 0x24,0xAe,0xB6, //1909
  31. 0x04,0xAe,0x4A, //1910
  32. 0x6A,0x4d,0xBe, //1911
  33. 0x0A,0x4d,0x52, //1912
  34. 0x0d,0x25,0x46, //1913
  35. 0x5d,0x52,0xBA, //1914
  36. 0x0B,0x54,0x4e, //1915
  37. 0x0d,0x6A,0x43, //1916
  38. 0x29,0x6d,0x37, //1917
  39. 0x09,0x5B,0x4B, //1918
  40. 0x74,0x9B,0xC1, //1919
  41. 0x04,0x97,0x54, //1920
  42. 0x0A,0x4B,0x48, //1921
  43. 0x5B,0x25,0xBC, //1922
  44. 0x06,0xA5,0x50, //1923
  45. 0x06,0xd4,0x45, //1924
  46. 0x4A,0xdA,0xB8, //1925
  47. 0x02,0xB6,0x4d, //1926
  48. 0x09,0x57,0x42, //1927
  49. 0x24,0x97,0xB7, //1928
  50. 0x04,0x97,0x4A, //1929
  51. 0x66,0x4B,0x3e, //1930
  52. 0x0d,0x4A,0x51, //1931
  53. 0x0e,0xA5,0x46, //1932
  54. 0x56,0xd4,0xBA, //1933
  55. 0x05,0xAd,0x4e, //1934
  56. 0x02,0xB6,0x44, //1935
  57. 0x39,0x37,0x38, //1936
  58. 0x09,0x2e,0x4B, //1937
  59. 0x7C,0x96,0xBf, //1938
  60. 0x0C,0x95,0x53, //1939
  61. 0x0d,0x4A,0x48, //1940
  62. 0x6d,0xA5,0x3B, //1941
  63. 0x0B,0x55,0x4f, //1942
  64. 0x05,0x6A,0x45, //1943
  65. 0x4A,0xAd,0xB9, //1944
  66. 0x02,0x5d,0x4d, //1945
  67. 0x09,0x2d,0x42, //1946
  68. 0x2C,0x95,0xB6, //1947
  69. 0x0A,0x95,0x4A, //1948
  70. 0x7B,0x4A,0xBd, //1949
  71. 0x06,0xCA,0x51, //1950
  72. 0x0B,0x55,0x46, //1951
  73. 0x55,0x5A,0xBB, //1952
  74. 0x04,0xdA,0x4e, //1953
  75. 0x0A,0x5B,0x43, //1954
  76. 0x35,0x2B,0xB8, //1955
  77. 0x05,0x2B,0x4C, //1956
  78. 0x8A,0x95,0x3f, //1957
  79. 0x0e,0x95,0x52, //1958
  80. 0x06,0xAA,0x48, //1959
  81. 0x7A,0xd5,0x3C, //1960
  82. 0x0A,0xB5,0x4f, //1961
  83. 0x04,0xB6,0x45, //1962
  84. 0x4A,0x57,0x39, //1963
  85. 0x0A,0x57,0x4d, //1964
  86. 0x05,0x26,0x42, //1965
  87. 0x3e,0x93,0x35, //1966
  88. 0x0d,0x95,0x49, //1967
  89. 0x75,0xAA,0xBe, //1968
  90. 0x05,0x6A,0x51, //1969
  91. 0x09,0x6d,0x46, //1970
  92. 0x54,0xAe,0xBB, //1971
  93. 0x04,0xAd,0x4f, //1972
  94. 0x0A,0x4d,0x43, //1973
  95. 0x4d,0x26,0xB7, //1974
  96. 0x0d,0x25,0x4B, //1975
  97. 0x8d,0x52,0xBf, //1976
  98. 0x0B,0x54,0x52, //1977
  99. 0x0B,0x6A,0x47, //1978
  100. 0x69,0x6d,0x3C, //1979
  101. 0x09,0x5B,0x50, //1980
  102. 0x04,0x9B,0x45, //1981
  103. 0x4A,0x4B,0xB9, //1982
  104. 0x0A,0x4B,0x4d, //1983
  105. 0xAB,0x25,0xC2, //1984
  106. 0x06,0xA5,0x54, //1985
  107. 0x06,0xd4,0x49, //1986
  108. 0x6A,0xdA,0x3d, //1987
  109. 0x0A,0xB6,0x51, //1988
  110. 0x09,0x37,0x46, //1989
  111. 0x54,0x97,0xBB, //1990
  112. 0x04,0x97,0x4f, //1991
  113. 0x06,0x4B,0x44, //1992
  114. 0x36,0xA5,0x37, //1993
  115. 0x0e,0xA5,0x4A, //1994
  116. 0x86,0xB2,0xBf, //1995
  117. 0x05,0xAC,0x53, //1996
  118. 0x0A,0xB6,0x47, //1997
  119. 0x59,0x36,0xBC, //1998
  120. 0x09,0x2e,0x50, //1999         
  121. 0x0C,0x96,0x45, //2000
  122. 0x4d,0x4A,0xB8, //2001
  123. 0x0d,0x4A,0x4C, //2002
  124. 0x0d,0xA5,0x41, //2003
  125. 0x25,0xAA,0xB6, //2004
  126. 0x05,0x6A,0x49, //2005
  127. 0x7A,0xAd,0xBd, //2006
  128. 0x02,0x5d,0x52, //2007
  129. 0x09,0x2d,0x47, //2008
  130. 0x5C,0x95,0xBA, //2009
  131. 0x0A,0x95,0x4e, //2010
  132. 0x0B,0x4A,0x43, //2011
  133. 0x4B,0x55,0x37, //2012
  134. 0x0A,0xd5,0x4A, //2013
  135. 0x95,0x5A,0xBf, //2014
  136. 0x04,0xBA,0x53, //2015
  137. 0x0A,0x5B,0x48, //2016
  138. 0x65,0x2B,0xBC, //2017
  139. 0x05,0x2B,0x50, //2018
  140. 0x0A,0x93,0x45, //2019
  141. 0x47,0x4A,0xB9, //2020
  142. 0x06,0xAA,0x4C, //2021
  143. 0x0A,0xd5,0x41, //2022
  144. 0x24,0xdA,0xB6, //2023
  145. 0x04,0xB6,0x4A, //2024
  146. 0x69,0x57,0x3d, //2025
  147. 0x0A,0x4e,0x51, //2026
  148. 0x0d,0x26,0x46, //2027
  149. 0x5e,0x93,0x3A, //2028
  150. 0x0d,0x53,0x4d, //2029
  151. 0x05,0xAA,0x43, //2030
  152. 0x36,0xB5,0x37, //2031
  153. 0x09,0x6d,0x4B, //2032
  154. 0xB4,0xAe,0xBf, //2033
  155. 0x04,0xAd,0x53, //2034
  156. 0x0A,0x4d,0x48, //2035
  157. 0x6d,0x25,0xBC, //2036
  158. 0x0d,0x25,0x4f, //2037
  159. 0x0d,0x52,0x44, //2038
  160. 0x5d,0xAA,0x38, //2039
  161. 0x0B,0x5A,0x4C, //2040
  162. 0x05,0x6d,0x41, //2041
  163. 0x24,0xAd,0xB6, //2042
  164. 0x04,0x9B,0x4A, //2043
  165. 0x7A,0x4B,0xBe, //2044
  166. 0x0A,0x4B,0x51, //2045
  167. 0x0A,0xA5,0x46, //2046
  168. 0x5B,0x52,0xBA, //2047
  169. 0x06,0xd2,0x4e, //2048
  170. 0x0A,0xdA,0x42, //2049
  171. 0x35,0x5B,0x37, //2050
  172. 0x09,0x37,0x4B, //2051
  173. 0x84,0x97,0xC1, //2052
  174. 0x04,0x97,0x53, //2053
  175. 0x06,0x4B,0x48, //2054
  176. 0x66,0xA5,0x3C, //2055
  177. 0x0e,0xA5,0x4f, //2056
  178. 0x06,0xB2,0x44, //2057
  179. 0x4A,0xB6,0x38, //2058
  180. 0x0A,0xAe,0x4C, //2059
  181. 0x09,0x2e,0x42, //2060
  182. 0x3C,0x97,0x35, //2061
  183. 0x0C,0x96,0x49, //2062
  184. 0x7d,0x4A,0xBd, //2063
  185. 0x0d,0x4A,0x51, //2064
  186. 0x0d,0xA5,0x45, //2065
  187. 0x55,0xAA,0xBA, //2066
  188. 0x05,0x6A,0x4e, //2067
  189. 0x0A,0x6d,0x43, //2068
  190. 0x45,0x2e,0xB7, //2069
  191. 0x05,0x2d,0x4B, //2070
  192. 0x8A,0x95,0xBf, //2071
  193. 0x0A,0x95,0x53, //2072
  194. 0x0B,0x4A,0x47, //2073
  195. 0x6B,0x55,0x3B, //2074
  196. 0x0A,0xd5,0x4f, //2075
  197. 0x05,0x5A,0x45, //2076
  198. 0x4A,0x5d,0x38, //2077
  199. 0x0A,0x5B,0x4C, //2078
  200. 0x05,0x2B,0x42, //2079
  201. 0x3A,0x93,0xB6, //2080
  202. 0x06,0x93,0x49, //2081
  203. 0x77,0x29,0xBd, //2082
  204. 0x06,0xAA,0x51, //2083
  205. 0x0A,0xd5,0x46, //2084
  206. 0x54,0xdA,0xBA, //2085
  207. 0x04,0xB6,0x4e, //2086
  208. 0x0A,0x57,0x43, //2087
  209. 0x45,0x27,0x38, //2088
  210. 0x0d,0x26,0x4A, //2089
  211. 0x8e,0x93,0x3e, //2090
  212. 0x0d,0x52,0x52, //2091
  213. 0x0d,0xAA,0x47, //2092
  214. 0x66,0xB5,0x3B, //2093
  215. 0x05,0x6d,0x4f, //2094
  216. 0x04,0xAe,0x45, //2095
  217. 0x4A,0x4e,0xB9, //2096
  218. 0x0A,0x4d,0x4C, //2097
  219. 0x0d,0x15,0x41, //2098
  220. 0x2d,0x92,0xB5, //2099
  221. 0x0d,0x53,0x49, //2100
  222. };

  223. uchar code Mon1[2][13]={0,31,28,31,30,31,30,31,31,30,31,30,31,
  224.                                   0,31,29,31,30,31,30,31,31,30,31,30,31};

  225. SPDATE Spdate;
  226. //獲得當年春節的公曆日期
  227. SPDATE GetSpringDay(uchar GreYear,uchar GreMon,uchar GreDay)
  228. {
  229.         //0x09,0x2d,0x47, //2008  0x47 01000111
  230.         int day;
  231.     uchar i,Flag,F;
  232.         uint Offset1;//出现问题在这里,原本定义为uchar类型,下面计算时超出范围导致错误,进行修改为uint类型后,验证正常
  233.         unsigned char L=0x01,Flag1=1;
  234.         unsigned int  Temp16,L1=0x0800;
  235.         //第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期
  236.         Spdate.cYear=GreYear ;
  237.         Spdate.cMon=(Data[(200-(100-GreYear)-1)*3+2]&0x60)>>5; //计算春节公历月份
  238.         Spdate.cDay=(Data[(200-(100-GreYear)-1)*3+2])&0x1f;    //计算春节公历日期

  239.         //判断平年,闰年
  240.         if( (!(GreYear%4) && (GreYear%100)) || !(GreYear%400) ) Flag=1;
  241.         else Flag=0;
  242.         
  243.         if(Spdate.cMon>GreMon)                                                                //春节离公历日期的天数
  244.         {
  245.            day=Mon1[Flag][GreMon]-GreDay;
  246.            for(i=GreMon+1;i<=Spdate.cMon-1;i++)
  247.                         day+=Mon1[Flag][i];
  248.            day+=Spdate.cDay;
  249.            F=1;
  250.         }
  251.         else if(Spdate.cMon<GreMon) //春節的月份小於目標的月份
  252.         {
  253.                 day=Mon1[Flag][Spdate.cMon]-Spdate.cDay;  
  254.                 for(i=Spdate.cMon+1;i<=GreMon-1;i++)
  255.                         day+=Mon1[Flag][i];
  256.                 day+=GreDay;                                //          000000000000000000000000000000000000000000000000000000000000000000
  257.                 F=0;
  258.         }
  259.         else
  260.         {
  261.                 if(Spdate.cDay>GreDay)
  262.                 {
  263.                         day=Spdate.cDay-GreDay;
  264.                         F=1;
  265.                 }
  266.                 else if(Spdate.cDay<GreDay)
  267.                 {
  268.                         day=GreDay-Spdate.cDay;
  269.                         F=0;
  270.                 }
  271.                 else day=0;
  272.         }                 

  273.         Spdate.cYear=Spdate.cYear;
  274.         Spdate.cMon=1;
  275.         Spdate.cDay=1;

  276.         if(!day) return Spdate ;

  277.         if(F)    //春节在公历日期后
  278.         {
  279.                 Spdate.cYear--;
  280.                 Spdate.cMon=12;
  281.                 //这边Offset1计算会出现超范围,因此把uchar类型改为uint后正常
  282.                 Offset1=(200-(100-Spdate.cYear)-1)*3;
  283.                 while(TRUE)
  284.                 {
  285.                         //格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
  286.                         //第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
  287.                         //0x4d,0x4A,0xB8, //2001
  288.                         if(Data[Offset1+1]&L)
  289.                                 day-=30;
  290.                         else
  291.                                 day-=29;
  292.                         L<<=1;
  293.                         if(((Data[Offset1+0]&0xf0)>>4)==Spdate.cMon && Flag1)//(Data[Offset1+0]&0xf0)>>4判断是否是闰月1平月0
  294.                         {
  295.                                 Flag1=0;
  296.                                 if(Data[Offset1+2]&0x80) day-=30; else day-=29;
  297.                                 continue;
  298.                         }
  299.                         if(day>0) Spdate.cMon--;
  300.                         else break;
  301.                         
  302.                         
  303.                 }
  304.                 Spdate.cDay=-day+1;
  305.         }
  306.         
  307.         if(!F)
  308.         {
  309.                 Spdate.cMon=1;
  310.                 //这边Offset1计算会出现超范围,因此把uchar类型改为uint后正常
  311.                 Offset1=(200-(100-Spdate.cYear)-1)*3;
  312.                 Temp16=(Data[Offset1+0]<<8)+Data[Offset1+1];
  313.                 while(TRUE)
  314.                 {
  315.                         if(Temp16 & L1) day-=30; else day-=29;
  316.                         if(day>=0)
  317.                                 Spdate.cMon++;
  318.                         else if(day<0)
  319.                         {
  320.                                 if(Temp16 & L1) day+=30; else day+=29;
  321.                                 break;
  322.                         }
  323.                         L1>>=1;
  324.                         //格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
  325.                         //第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
  326.                         if(((Data[Offset1+0]&0xf0)>>4)==(Spdate.cMon-1) && Flag1) //闰月
  327.                         {
  328.                                 Flag1=0;
  329.                                 Spdate.cMon--;
  330.                                 if(Temp16 & L1) day-=30; else day-=29;
  331.                                 if(day>=0)
  332.                                         Spdate.cMon++;
  333.                                 else if(day<0)
  334.                                 {
  335.                                         if(Temp16 & L1) day+=30; else day+=29;
  336.                                         break;
  337.                                 }
  338.                                 L1>>=1;
  339.                         }
  340.                 }
  341.                 Spdate.cDay=day+1;
  342.         }
  343.     return Spdate;
  344. }

  345. bit YearFlag(uchar cYear) //判断平年,闰年
  346. {
  347.    if( (!(cYear%4) && (cYear%100)) || !(cYear%400) ) return 1; else return 0;
  348. }

  349. //目標日期是星期幾
  350. uchar GetWeekDay(uchar cYear,uchar cMon,uchar cDay)
  351. {
  352.         char i;
  353.         int  Sum=0,tmpyear=2000+cYear;
  354.         for(i=1;i<=cMon-1;i++)
  355.                 Sum+=Mon1[YearFlag(cYear)][i];
  356.         Sum+=cDay-1;
  357.         
  358.         return (((tmpyear-1)+(tmpyear-1)/4-(tmpyear-1)/100+(tmpyear-1)/400+Sum)%7)+1;
  359. }

  360. void main()
  361. {
  362.         for(;;)
  363.         {
  364.         GetSpringDay(18,12,30);        //输入数据为十进制,不是BCD码格式,这个请注意

  365.         }
  366. }

  367. /*****************************************************************************

  368. 首先要能记住十大天干和十二地支,
  369. 十天干:  甲、乙、丙、丁、戊、己、庚、辛、壬、癸;
  370. 十二地支:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥;

  371. 天干地支纪年法首先是天干在前,地支在后,比如今年2005就为-乙酉年,先来算算天干,
  372. 有个公式:
  373. 4、 5、 6、 7、 8、 9、 0、 1、 2、 3 对应的十天干就是
  374. 甲、乙、丙、丁、戊、己、庚、辛、壬、癸,
  375. 数字为年代的最后的一位数字,比如今年是2005,最后一位是5,对应的天干就是乙;

  376. 地支的算法:用年代数除以12,后面的余数就代表某个地支,
  377. 余数分别为:4、 5、 6、 7、 8、 9、 10、 11、 0(能整除)、1、 2、3.
  378. 代表地支为:子、丑、寅、卯、辰、巳、午、 未、 申、酉、戌、亥.
  379. 比如2005年为例:年代末尾数为5,对应的天干为乙,2005除以12,余数为1,对应的地支为酉,所以2005年为乙酉年。

  380. ******************************************************************************/
复制代码

全部资料51hei下载地址:
4545456.rar (10.77 KB, 下载次数: 104)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:205015 发表于 2019-4-13 08:49 | 显示全部楼层
感谢代码开源分享,尝试一下。
回复

使用道具 举报

ID:350962 发表于 2019-10-29 23:57 | 显示全部楼层
本帖最后由 ac9979 于 2019-11-5 22:09 编辑

前段时间用STC15L104W改了一个时钟,增加了农历显示功能,参照了你的程序,但是文件大小超出了范围,只好想办法精简程序,发现如果农历年和阳历不是同一年,可以递归调用本函数 GetSpringDay(GreYear+1, GreMon+12, GreDay),代码会少30%,这个判断就不需要了:  if(F)    //春节在公历日期后{ ……} 。
具体代码如下:





typedef unsigned int u16;  //16位无符号整型数
typedef unsigned char u8;  //8位无符号整型数


u8 dn(u8 yy,u8 mm,u8 dd);                                   //公历转农历函数
u8 temp;
u8 NonY=0;                                                     //农历年
u8 NonM=0;                                                     //农历月
u8 NonD=0;                                                     //农历日


u16 nday[]={0,31,59,90,120,151,181,212,243,273,304,334,365,396};     //第n-1月有多少天

       
//公历年对应的农历数据,每年三字节,
//格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
//第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
//月份对应的位为1 表示本农历月大(30 天),为0 表示小(29 天).
//第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期       


u8 code Data[]={   
0x0C,0x96,0x45, //2000
0x4d,0x4A,0xB8, //2001
0x0d,0x4A,0x4C, //2002
0x0d,0xA5,0x41, //2003
0x25,0xAA,0xB6, //2004
0x05,0x6A,0x49, //2005
0x7A,0xAd,0xBd, //2006
0x02,0x5d,0x52, //2007
0x09,0x2d,0x47, //2008
0x5C,0x95,0xBA, //2009
0x0A,0x95,0x4e, //2010
0x0B,0x4A,0x43, //2011
0x4B,0x55,0x37, //2012
0x0A,0xd5,0x4A, //2013
0x95,0x5A,0xBf, //2014
0x04,0xBA,0x53, //2015
0x0A,0x5B,0x48, //2016
0x65,0x2B,0xBC, //2017
0x05,0x2B,0x50, //2018
0x0A,0x93,0x45, //2019
0x47,0x4A,0xB9, //2020
0x06,0xAA,0x4C, //2021
0x0A,0xd5,0x41, //2022
0x24,0xdA,0xB6, //2023
0x04,0xB6,0x4A, //2024
0x69,0x57,0x3d, //2025
0x0A,0x4e,0x51, //2026
0x0d,0x26,0x46, //2027
0x5e,0x93,0x3A, //2028
0x0d,0x53,0x4d, //2029
0x05,0xAA,0x43, //2030
0x36,0xB5,0x37, //2031
0x09,0x6d,0x4B, //2032
0xB4,0xAe,0xBf, //2033
0x04,0xAd,0x53, //2034
0x0A,0x4d,0x48, //2035
0x6d,0x25,0xBC, //2036
0x0d,0x25,0x4f, //2037
0x0d,0x52,0x44, //2038
0x5d,0xAA,0x38, //2039
0x0B,0x5A,0x4C, //2040
0x05,0x6d,0x41, //2041
0x24,0xAd,0xB6, //2042
0x04,0x9B,0x4A, //2043
0x7A,0x4B,0xBe, //2044
0x0A,0x4B,0x51, //2045
0x0A,0xA5,0x46, //2046
0x5B,0x52,0xBA, //2047
0x06,0xd2,0x4e, //2048
0x0A,0xdA,0x42, //2049
0x35,0x5B,0x37, //2050
0x09,0x37,0x4B, //2051
0x84,0x97,0xC1, //2052
0x04,0x97,0x53, //2053
0x06,0x4B,0x48, //2054
0x66,0xA5,0x3C, //2055
0x0e,0xA5,0x4f, //2056
0x06,0xB2,0x44, //2057
0x4A,0xB6,0x38, //2058
0x0A,0xAe,0x4C, //2059
0x09,0x2e,0x42, //2060
0x3C,0x97,0x35, //2061
0x0C,0x96,0x49, //2062
0x7d,0x4A,0xBd, //2063
0x0d,0x4A,0x51, //2064
0x0d,0xA5,0x45, //2065
0x55,0xAA,0xBA, //2066
0x05,0x6A,0x4e, //2067
0x0A,0x6d,0x43, //2068
0x45,0x2e,0xB7, //2069
0x05,0x2d,0x4B, //2070
0x8A,0x95,0xBf, //2071
0x0A,0x95,0x53, //2072
0x0B,0x4A,0x47, //2073
0x6B,0x55,0x3B, //2074
0x0A,0xd5,0x4f, //2075
0x05,0x5A,0x45, //2076
0x4A,0x5d,0x38, //2077
0x0A,0x5B,0x4C, //2078
0x05,0x2B,0x42, //2079
0x3A,0x93,0xB6, //2080
0x06,0x93,0x49, //2081
0x77,0x29,0xBd, //2082
0x06,0xAA,0x51, //2083
0x0A,0xd5,0x46, //2084
0x54,0xdA,0xBA, //2085
0x04,0xB6,0x4e, //2086
0x0A,0x57,0x43, //2087
0x45,0x27,0x38, //2088
0x0d,0x26,0x4A, //2089
0x8e,0x93,0x3e, //2090
0x0d,0x52,0x52, //2091
0x0d,0xAA,0x47, //2092
0x66,0xB5,0x3B, //2093
0x05,0x6d,0x4f, //2094
0x04,0xAe,0x45, //2095
0x4A,0x4e,0xB9, //2096
0x0A,0x4d,0x4C, //2097
0x0d,0x15,0x41, //2098
0x2d,0x92,0xB5, //2099
};


u8 dn(u8 yy,u8 mm,u8 dd)
{
        u16        nyear=2000+yy;              //仅计算2000~2099年
        bit RunY=0;                     //公历闰年标志
        bit Flag1=1;                    //农历闰月标志
        u8 SpM;                         //春节公历月份
        u8 SpD;                         //春节公历日期
        u8 SpN;                                                                                                  //春节是本公历年第几天
       
        u8 RunM=0;                                                                            //农历闰月月份       
       
        int Diff;
        int day;
       
        u16 CuN;                                                            //当前日期是本公历年第几天
        u16 Offset1;
        u16 Temp16;
        u16 L1=0x8000;
       
       

       
       
       
        SpM=(Data[yy*3+2]&0x60)>>5; //计算春节公历月份       
        SpD=(Data[yy*3+2])&0x1f;    //计算春节公历日期       
        SpN=nday[SpM-1]+SpD;                                //计算春节是本年第几天,因为春节永远在公历3月前,所以不用考虑2月是28天还是29天
       
        //判断本公历年是否闰年
        if ( nyear %4 ==0   &&         nyear % 100 !=0 )
                RunY=1;
        if ( nyear % 400 ==0   )
                RunY=1;
       
        //计算当前日期本公历年第几天
        if ( RunY==1 && mm > 2 )
                CuN=nday[mm-1]+dd+1;         
        else
                CuN=nday[mm-1]+dd;
       
               
        Diff=CuN-SpN;                                                                   //计算当前日期与春节相差多少天
       
       
        if( Diff >=0 )       
        {       
                        NonY=yy;
                        day=Diff;
                        NonM=1;
                        Offset1=(yy)*3;       
               
                        //格式第一字节BIT3-0 对应农历第1-4 月的大小
                        //第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
                        Temp16=((Data[Offset1+0]&0x0f)<<12)+(Data[Offset1+1]<<4)+((Data[Offset1+2]&0xf0)>>4);                                                                


                        while ( 1 )
                        {
                                                        if(Temp16 & L1) day-=30; else day-=29;
                               
                                                        if(day>=0)
                                                                        NonM++;
                                                        else if(day<0)
                                                        {
                                                                        if(Temp16 & L1) day+=30; else day+=29;
                                                                        break;
                                                        }
                                                        L1>>=1;
                                                       
                                                        //格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月
                                                        if(((Data[Offset1+0]&0xf0)>>4)==(NonM-1) && Flag1) // 闰月,幸好从来不闰正月
                                                        {
                                                                                        Flag1=0;
                                                                                        NonM--;
                                                                                        RunM=NonM;                                                                                       
                                                        }
                        }
                        NonD=day+1;       
                       
        }
        else   //如果当前日期还在春节前,则农历还是上一年,公历月份增加12个月,然后递归调用
        {
                        RunM = dn( yy-1,mm+12,dd );               
               
        }



        return(RunM);       
}

       
       

void main()
{

        temp=dn( 18 ,10 ,12 );   //调用公历转农历函数,返回值为闰月月份,如果日期在闰月之前,则返回值为0;
               
        if( temp == NonM )
                                        ;                //表示此月是闰月
        else
                                        ;
       
       
}
  

Clock.rar

2.07 KB, 下载次数: 40, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:268118 发表于 2019-11-2 00:35 | 显示全部楼层
感謝兩位版主的分享。
回复

使用道具 举报

ID:584814 发表于 2020-2-16 20:05 | 显示全部楼层
星期也可以通过日期来计算的,而且算法简单(蔡勒Zeller公式)。
回复

使用道具 举报

ID:721769 发表于 2021-6-6 17:57 | 显示全部楼层
基姆拉尔森 星期计算公式& 蔡勒 星期计算公式, 其实都是大同小异的

  1. /*        @funciton: Calculate weekday in KimLarsen formula
  2.         @parameters: year, month, day
  3.         @return: weekday
  4. */
  5. int calculateWeekByKimLarsen(int year, int month, int day)
  6. {
  7.         int iY = year, iM = month, iD = day, iWeekDay;

  8.         if (1 == iM || 2 == iM){   
  9.         iM += 12;
  10.         iY--;
  11.     }
  12.     iWeekDay = (iD + 1 + iM*2 + 3*(iM+1)/5 + iY + iY/4 - iY/100 + iY/400) % 7;

  13.     return iWeekDay;
  14. }

  15. /*        @funciton: Calculate weekday in Zella formula
  16.         @parameters: year, month, day
  17.         @return: weekday
  18. */
  19. int calculateWeekByZella( int year , int month, int day )
  20. {
  21.         int c,y,week;

  22.         if (month == 1 || month == 2){
  23.                 year--;
  24.                 month += 12;
  25.         }
  26.         c = year / 100;
  27.         y = year - c * 100;
  28.         week = y + y/4 + c/4 - 2*c + 26*(month+1)/10 + day - 1;
  29.         while (week<0){
  30.                 week += 7;
  31.         }
  32.         week %= 7;

  33.         return (week);
  34. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表