数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 2515|回复: 39

[C51] 1901年~2099年公历转农历程序

[复制链接]
发表于 2024-10-22 12:50:37 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
本帖最后由 mmxx2015 于 2024-10-22 18:10 编辑

搜索公历转农历方法时,多数结果使用的是查表法,即预置N年的农历特征数据,然后根据这些特征数据把N年内其中任意一天的公历转换为农历。

其中,找到的这篇文章的程序比较容易看懂:
公农历转换和获取二十四节气算法

https://blog.csdn.net/qq_46041930/article/details/108653836
文章中还有转换农历二十四节气和星期日,以下程序没有包含这两段,需要的可以查看原文。


实际测试也发现一些问题:
(1)农历特征表格有6年的数据错误。
  1. 1960年 闰六月
  2. 错误数据:{0x7A, 0xD5, 0x3C},    /* 060-1960 */
  3. 正确数据:{0x6A, 0xD5, 0x3C},    /* 060-1960 */

  4. 1989年 六月大,七月小
  5. 错误数据:{0x09, 0x37, 0x46},    /* 089-1989 */
  6. 正确数据:{0x09, 0x57, 0x46},    /* 089-1989 */
  7. 0x937=1001,0011,0111
  8. 0x957=1001,0101,0111

  9. 2025年 闰六月 三月大,四月小
  10. 错误数据:{0x69, 0x57, 0x3D},    /* 125-2025 */
  11. 正确数据:{0x6A, 0x57, 0x3D},    /* 125-2025 */
  12. 0x957=1001,0101,0111
  13. 0x95A=1010,0101,0111

  14. 2057年 八月小,九月大
  15. 错误数据:{0x06, 0xB2, 0x44},    /* 157-2057 */
  16. 正确数据:{0x06, 0xAA, 0x44},    /* 157-2057 */
  17. 0x6B2=0110,1011,0010
  18. 0x6AA=0110,1010,1010

  19. 2089年 七月小,八月大
  20. 错误数据:{0x0D, 0x26, 0x4A},    /* 189-2089 */
  21. 正确数据:{0x0D, 0x16, 0x4A},    /* 189-2089 */
  22. 0xD26=1101,0010,0110
  23. 0xD16=1101,0001,0110

  24. 2097年  六月小,七月大
  25. 错误数据:{0x0A, 0x4D, 0x4C},    /* 197-2097 */
  26. 正确数据:{0x0A, 0x2D, 0x4C},    /* 197-2097 */
  27. 0xA4D=1010,0100,1101
  28. 0xA2D=1010,0010,1101
复制代码
(2)表格少1900年,无法转换1901年春节前的农历(需要上一年的农历数据)。
(3)有农历闰月的年份,常规月和闰月均记为闰月,比如2025年六月和闰六月均记为闰月。

一下程序修正了上述问题,添加更详细的注释,部分数据使用结构体使之更容易理解。
经过把公历1901.1.1~2099.12.31转成农历串口输出与从农历查询网http://cn.nongli.info/提取的数据对比,数据一致(顺便说一下,我从网上下载的一份“公历农历对照表 ExcelHome”表格中1960年闰七月是错误的,1960年是闰六月,这份文件可能来着 ExcelHome,可能新版已修正,但因为要注册才能下载,所以未验证)。


程序组成(可按需放在一个或多个文件中):

  1. //******************************************************************
  2. //        结构体/联合体声明
  3. //******************************************************************

  4. //农历特征数据结构体
  5. typedef struct
  6. {
  7.         union
  8.         {
  9.                 unsigned char        V8;

  10.                 struct
  11.                 {
  12.                         unsigned char        Month_1_4_Long_Short:4;                //字节0 bit[3:0],农历第1-4月的大小
  13.                         unsigned char        Leap_Month:4;                        //字节0 bit[7:4],闰月月份,0表示无闰月
  14.                 }Bits;
  15.         }Byte_0;

  16.         unsigned char        Month_5_12_Long_Short;                                //字节1,农历第5-12月大小

  17.         union
  18.         {
  19.                 unsigned char        V8;

  20.                 struct
  21.                 {
  22.                         unsigned char        Spring_Festival_Date:5;                //字节2 bit[4:0],春节的公历日期
  23.                         unsigned char        Spring_Festival_Month:2;        //字节2 bit[6:5],春节的公历月份
  24.                         unsigned char        Month_13_Long_Short:1;                //字节2 bit7,农历第13个月大小
  25.                 }Bits;
  26.         }Byte_2;
  27. }Lunar_Year_Code_Typedef;


  28. //公历转农历返回数据结构体
  29. typedef struct
  30. {
  31.         unsigned char        Month:5;                //月
  32.         unsigned char        IS_Leap_Month:1;        //闰月标志
  33.         unsigned char        Reserved_Bits:2;
  34.         unsigned char        Date:8;                        //日
  35. }Solar2Lunar_Typedef;
复制代码
  1. //位值
  2. #define        BIT0        0x01
  3. #define        BIT1        0x02
  4. #define        BIT2        0x04
  5. #define        BIT3        0x08
  6. #define        BIT4        0x10
  7. #define        BIT5        0x20
  8. #define        BIT6        0x40
  9. #define        BIT7        0x80

  10. #define        BIT8        0x0100
  11. #define        BIT9        0x0200
  12. #define        BIT10        0x0400
  13. #define        BIT11        0x0800
  14. #define        BIT12        0x1000
  15. #define        BIT13        0x2000
  16. #define        BIT14        0x4000
  17. #define        BIT15        0x8000
复制代码
  1. //******************************************************************
  2. //* 公历与农历转换年份数据存储数组
  3. //* 公历年对应的农历数据,每年三字节,
  4. //* 格式第一字节BIT7-4 位表示闰月月份,值为0为无闰月,BIT3-0对应农历第1-4月的大小
  5. //* 第二字节BIT7-0对应农历第5-12月大小,第三字节BIT7表示农历第13个月大小
  6. //* 月份对应的位为1表示本农历月大(30天),为0表示小(29天).
  7. //* 第三字节BIT6-5表示春节的公历月份,BIT4-0表示春节的公历日期
  8. //******************************************************************
  9. //农历特征数据表格(1900年~2099年)
  10. Lunar_Year_Code_Typedef code Lunar_Year_Code[200] =
  11. {
  12.         {0x84, 0xB6, 0xBF},        /* 000-1900 */
  13.         {0x04, 0xAE, 0x53},        /* 001-1901 */
  14.         {0x0A, 0x57, 0x48},        /* 002-1902 */
  15.         {0x55, 0x26, 0xBD},        /* 003-1903 */
  16.         {0x0D, 0x26, 0x50},        /* 004-1904 */
  17.         {0x0D, 0x95, 0x44},        /* 005-1905 */
  18.         {0x46, 0xAA, 0xB9},        /* 006-1906 */
  19.         {0x05, 0x6A, 0x4D},        /* 007-1907 */
  20.         {0x09, 0xAD, 0x42},        /* 008-1908 */
  21.         {0x24, 0xAE, 0xB6},        /* 009-1909 */
  22.         {0x04, 0xAE, 0x4A},        /* 010-1910 */
  23.         {0x6A, 0x4D, 0xBE},        /* 011-1911 */
  24.         {0x0A, 0x4D, 0x52},        /* 012-1912 */
  25.         {0x0D, 0x25, 0x46},        /* 013-1913 */
  26.         {0x5D, 0x52, 0xBA},        /* 014-1914 */
  27.         {0x0B, 0x54, 0x4E},        /* 015-1915 */
  28.         {0x0D, 0x6A, 0x43},        /* 016-1916 */
  29.         {0x29, 0x6D, 0x37},        /* 017-1917 */
  30.         {0x09, 0x5B, 0x4B},        /* 018-1918 */
  31.         {0x74, 0x9B, 0xC1},        /* 019-1919 */
  32.         {0x04, 0x97, 0x54},        /* 020-1920 */
  33.         {0x0A, 0x4B, 0x48},        /* 021-1921 */
  34.         {0x5B, 0x25, 0xBC},        /* 022-1922 */
  35.         {0x06, 0xA5, 0x50},        /* 023-1923 */
  36.         {0x06, 0xD4, 0x45},        /* 024-1924 */
  37.         {0x4A, 0xDA, 0xB8},        /* 025-1925 */
  38.         {0x02, 0xB6, 0x4D},        /* 026-1926 */
  39.         {0x09, 0x57, 0x42},        /* 027-1927 */
  40.         {0x24, 0x97, 0xB7},        /* 028-1928 */
  41.         {0x04, 0x97, 0x4A},        /* 029-1929 */
  42.         {0x66, 0x4B, 0x3E},        /* 030-1930 */
  43.         {0x0D, 0x4A, 0x51},        /* 031-1931 */
  44.         {0x0E, 0xA5, 0x46},        /* 032-1932 */
  45.         {0x56, 0xD4, 0xBA},        /* 033-1933 */
  46.         {0x05, 0xAD, 0x4E},        /* 034-1934 */
  47.         {0x02, 0xB6, 0x44},        /* 035-1935 */
  48.         {0x39, 0x37, 0x38},        /* 036-1936 */
  49.         {0x09, 0x2E, 0x4B},        /* 037-1937 */
  50.         {0x7C, 0x96, 0xBF},        /* 038-1938 */
  51.         {0x0C, 0x95, 0x53},        /* 039-1939 */
  52.         {0x0D, 0x4A, 0x48},        /* 040-1940 */
  53.         {0x6D, 0xA5, 0x3B},        /* 041-1941 */
  54.         {0x0B, 0x55, 0x4F},        /* 042-1942 */
  55.         {0x05, 0x6A, 0x45},        /* 043-1943 */
  56.         {0x4A, 0xAD, 0xB9},        /* 044-1944 */
  57.         {0x02, 0x5D, 0x4D},        /* 045-1945 */
  58.         {0x09, 0x2D, 0x42},        /* 046-1946 */
  59.         {0x2C, 0x95, 0xB6},        /* 047-1947 */
  60.         {0x0A, 0x95, 0x4A},        /* 048-1948 */
  61.         {0x7B, 0x4A, 0xBD},        /* 049-1949 */
  62.         {0x06, 0xCA, 0x51},        /* 050-1950 */
  63.         {0x0B, 0x55, 0x46},        /* 051-1951 */
  64.         {0x55, 0x5A, 0xBB},        /* 052-1952 */
  65.         {0x04, 0xDA, 0x4E},        /* 053-1953 */
  66.         {0x0A, 0x5B, 0x43},        /* 054-1954 */
  67.         {0x35, 0x2B, 0xB8},        /* 055-1955 */
  68.         {0x05, 0x2B, 0x4C},        /* 056-1956 */
  69.         {0x8A, 0x95, 0x3F},        /* 057-1957 */
  70.         {0x0E, 0x95, 0x52},        /* 058-1958 */
  71.         {0x06, 0xAA, 0x48},        /* 059-1959 */
  72.         {0x6A, 0xD5, 0x3C},        /* 060-1960 */
  73.         {0x0A, 0xB5, 0x4F},        /* 061-1961 */
  74.         {0x04, 0xB6, 0x45},        /* 062-1962 */
  75.         {0x4A, 0x57, 0x39},        /* 063-1963 */
  76.         {0x0A, 0x57, 0x4D},        /* 064-1964 */
  77.         {0x05, 0x26, 0x42},        /* 065-1965 */
  78.         {0x3E, 0x93, 0x35},        /* 066-1966 */
  79.         {0x0D, 0x95, 0x49},        /* 067-1967 */
  80.         {0x75, 0xAA, 0xBE},        /* 068-1968 */
  81.         {0x05, 0x6A, 0x51},        /* 069-1969 */
  82.         {0x09, 0x6D, 0x46},        /* 070-1970 */
  83.         {0x54, 0xAE, 0xBB},        /* 071-1971 */
  84.         {0x04, 0xAD, 0x4F},        /* 072-1972 */
  85.         {0x0A, 0x4D, 0x43},        /* 073-1973 */
  86.         {0x4D, 0x26, 0xB7},        /* 074-1974 */
  87.         {0x0D, 0x25, 0x4B},        /* 075-1975 */
  88.         {0x8D, 0x52, 0xBF},        /* 076-1976 */
  89.         {0x0B, 0x54, 0x52},        /* 077-1977 */
  90.         {0x0B, 0x6A, 0x47},        /* 078-1978 */
  91.         {0x69, 0x6D, 0x3C},        /* 079-1979 */
  92.         {0x09, 0x5B, 0x50},        /* 080-1980 */
  93.         {0x04, 0x9B, 0x45},        /* 081-1981 */
  94.         {0x4A, 0x4B, 0xB9},        /* 082-1982 */
  95.         {0x0A, 0x4B, 0x4D},        /* 083-1983 */
  96.         {0xAB, 0x25, 0xC2},        /* 084-1984 */
  97.         {0x06, 0xA5, 0x54},        /* 085-1985 */
  98.         {0x06, 0xD4, 0x49},        /* 086-1986 */
  99.         {0x6A, 0xDA, 0x3D},        /* 087-1987 */
  100.         {0x0A, 0xB6, 0x51},        /* 088-1988 */
  101.         {0x09, 0x57, 0x46},        /* 089-1989 */
  102.         {0x54, 0x97, 0xBB},        /* 090-1990 */
  103.         {0x04, 0x97, 0x4F},        /* 091-1991 */
  104.         {0x06, 0x4B, 0x44},        /* 092-1992 */
  105.         {0x36, 0xA5, 0x37},        /* 093-1993 */
  106.         {0x0E, 0xA5, 0x4A},        /* 094-1994 */
  107.         {0x86, 0xB2, 0xBF},        /* 095-1995 */
  108.         {0x05, 0xAC, 0x53},        /* 096-1996 */
  109.         {0x0A, 0xB6, 0x47},        /* 097-1997 */
  110.         {0x59, 0x36, 0xBC},        /* 098-1998 */
  111.         {0x09, 0x2E, 0x50},        /* 099-1999 */
  112.         {0x0C, 0x96, 0x45},        /* 100-2000 */
  113.         {0x4D, 0x4A, 0xB8},        /* 101-2001 */
  114.         {0x0D, 0x4A, 0x4C},        /* 102-2002 */
  115.         {0x0D, 0xA5, 0x41},        /* 103-2003 */
  116.         {0x25, 0xAA, 0xB6},        /* 104-2004 */
  117.         {0x05, 0x6A, 0x49},        /* 105-2005 */
  118.         {0x7A, 0xAD, 0xBD},        /* 106-2006 */
  119.         {0x02, 0x5D, 0x52},        /* 107-2007 */
  120.         {0x09, 0x2D, 0x47},        /* 108-2008 */
  121.         {0x5C, 0x95, 0xBA},        /* 109-2009 */
  122.         {0x0A, 0x95, 0x4E},        /* 110-2010 */
  123.         {0x0B, 0x4A, 0x43},        /* 111-2011 */
  124.         {0x4B, 0x55, 0x37},        /* 112-2012 */
  125.         {0x0A, 0xD5, 0x4A},        /* 113-2013 */
  126.         {0x95, 0x5A, 0xBF},        /* 114-2014 */
  127.         {0x04, 0xBA, 0x53},        /* 115-2015 */
  128.         {0x0A, 0x5B, 0x48},        /* 116-2016 */
  129.         {0x65, 0x2B, 0xBC},        /* 117-2017 */
  130.         {0x05, 0x2B, 0x50},        /* 118-2018 */
  131.         {0x0A, 0x93, 0x45},        /* 119-2019 */
  132.         {0x47, 0x4A, 0xB9},        /* 120-2020 */
  133.         {0x06, 0xAA, 0x4C},        /* 121-2021 */
  134.         {0x0A, 0xD5, 0x41},        /* 122-2022 */
  135.         {0x24, 0xDA, 0xB6},        /* 123-2023 */
  136.         {0x04, 0xB6, 0x4A},        /* 124-2024 */
  137.         {0x6A, 0x57, 0x3D},        /* 125-2025 */
  138.         {0x0A, 0x4E, 0x51},        /* 126-2026 */
  139.         {0x0D, 0x26, 0x46},        /* 127-2027 */
  140.         {0x5E, 0x93, 0x3A},        /* 128-2028 */
  141.         {0x0D, 0x53, 0x4D},        /* 129-2029 */
  142.         {0x05, 0xAA, 0x43},        /* 130-2030 */
  143.         {0x36, 0xB5, 0x37},        /* 131-2031 */
  144.         {0x09, 0x6D, 0x4B},        /* 132-2032 */
  145.         {0xB4, 0xAE, 0xBF},        /* 133-2033 */
  146.         {0x04, 0xAD, 0x53},        /* 134-2034 */
  147.         {0x0A, 0x4D, 0x48},        /* 135-2035 */
  148.         {0x6D, 0x25, 0xBC},        /* 136-2036 */
  149.         {0x0D, 0x25, 0x4F},        /* 137-2037 */
  150.         {0x0D, 0x52, 0x44},        /* 138-2038 */
  151.         {0x5D, 0xAA, 0x38},        /* 139-2039 */
  152.         {0x0B, 0x5A, 0x4C},        /* 140-2040 */
  153.         {0x05, 0x6D, 0x41},        /* 141-2041 */
  154.         {0x24, 0xAD, 0xB6},        /* 142-2042 */
  155.         {0x04, 0x9B, 0x4A},        /* 143-2043 */
  156.         {0x7A, 0x4B, 0xBE},        /* 144-2044 */
  157.         {0x0A, 0x4B, 0x51},        /* 145-2045 */
  158.         {0x0A, 0xA5, 0x46},        /* 146-2046 */
  159.         {0x5B, 0x52, 0xBA},        /* 147-2047 */
  160.         {0x06, 0xD2, 0x4E},        /* 148-2048 */
  161.         {0x0A, 0xDA, 0x42},        /* 149-2049 */
  162.         {0x35, 0x5B, 0x37},        /* 150-2050 */
  163.         {0x09, 0x37, 0x4B},        /* 151-2051 */
  164.         {0x84, 0x97, 0xC1},        /* 152-2052 */
  165.         {0x04, 0x97, 0x53},        /* 153-2053 */
  166.         {0x06, 0x4B, 0x48},        /* 154-2054 */
  167.         {0x66, 0xA5, 0x3C},        /* 155-2055 */
  168.         {0x0E, 0xA5, 0x4F},        /* 156-2056 */
  169.         {0x06, 0xAA, 0x44},        /* 157-2057 */
  170.         {0x4A, 0xB6, 0x38},        /* 158-2058 */
  171.         {0x0A, 0xAE, 0x4C},        /* 159-2059 */
  172.         {0x09, 0x2E, 0x42},        /* 160-2060 */
  173.         {0x3C, 0x97, 0x35},        /* 161-2061 */
  174.         {0x0C, 0x96, 0x49},        /* 162-2062 */
  175.         {0x7D, 0x4A, 0xBD},        /* 163-2063 */
  176.         {0x0D, 0x4A, 0x51},        /* 164-2064 */
  177.         {0x0D, 0xA5, 0x45},        /* 165-2065 */
  178.         {0x55, 0xAA, 0xBA},        /* 166-2066 */
  179.         {0x05, 0x6A, 0x4E},        /* 167-2067 */
  180.         {0x0A, 0x6D, 0x43},        /* 168-2068 */
  181.         {0x45, 0x2E, 0xB7},        /* 169-2069 */
  182.         {0x05, 0x2D, 0x4B},        /* 170-2070 */
  183.         {0x8A, 0x95, 0xBF},        /* 171-2071 */
  184.         {0x0A, 0x95, 0x53},        /* 172-2072 */
  185.         {0x0B, 0x4A, 0x47},        /* 173-2073 */
  186.         {0x6B, 0x55, 0x3B},        /* 174-2074 */
  187.         {0x0A, 0xD5, 0x4F},        /* 175-2075 */
  188.         {0x05, 0x5A, 0x45},        /* 176-2076 */
  189.         {0x4A, 0x5D, 0x38},        /* 177-2077 */
  190.         {0x0A, 0x5B, 0x4C},        /* 178-2078 */
  191.         {0x05, 0x2B, 0x42},        /* 179-2079 */
  192.         {0x3A, 0x93, 0xB6},        /* 180-2080 */
  193.         {0x06, 0x93, 0x49},        /* 181-2081 */
  194.         {0x77, 0x29, 0xBD},        /* 182-2082 */
  195.         {0x06, 0xAA, 0x51},        /* 183-2083 */
  196.         {0x0A, 0xD5, 0x46},        /* 184-2084 */
  197.         {0x54, 0xDA, 0xBA},        /* 185-2085 */
  198.         {0x04, 0xB6, 0x4E},        /* 186-2086 */
  199.         {0x0A, 0x57, 0x43},        /* 187-2087 */
  200.         {0x45, 0x27, 0x38},        /* 188-2088 */
  201.         {0x0D, 0x16, 0x4A},        /* 189-2089 */
  202.         {0x8E, 0x93, 0x3E},        /* 190-2090 */
  203.         {0x0D, 0x52, 0x52},        /* 191-2091 */
  204.         {0x0D, 0xAA, 0x47},        /* 192-2092 */
  205.         {0x66, 0xB5, 0x3B},        /* 193-2093 */
  206.         {0x05, 0x6D, 0x4F},        /* 194-2094 */
  207.         {0x04, 0xAE, 0x45},        /* 195-2095 */
  208.         {0x4A, 0x4E, 0xB9},        /* 196-2096 */
  209.         {0x0A, 0x2D, 0x4C},        /* 197-2097 */
  210.         {0x0D, 0x15, 0x41},        /* 198-2098 */
  211.         {0x2D, 0x92, 0xB5},        /* 199-2099 */
  212. };


  213. //公历前n月总天数
  214. unsigned int code Days_Code[13] =
  215. {
  216.         0,        //0
  217.         0,        //1,1月:当月
  218.         31,        //2,1月:31
  219.         59,        //3,1~2月:31+28=59
  220.         90,        //4,1~3月:31+28+31=90
  221.         120,        //5,1~4月:31+28+31+30=120
  222.         151,        //6,1~5月:31+28+31+30+31=151
  223.         181,        //7,1~6月:31+28+31+30+31+30=181
  224.         212,        //8,1~7月:31+28+31+30+31+30+31=212
  225.         243,        //9,1~8月:31+28+31+30+31+30+31+31=243
  226.         273,        //10,1~9月:31+28+31+30+31+30+31+31+30=273
  227.         304,        //11,1~10月:31+28+31+30+31+30+31+31+30+31=304
  228.         334,        //12,1~11月:31+28+31+30+31+30+31+31+30+31+30=334
  229. };


  230. //农历大小月特征位编码
  231. unsigned char code Month_Long_Short_Bit_Table[14] =
  232. {
  233.         0x00,                //0
  234.         BIT3,                //1,1月
  235.         BIT2,                //2,2月
  236.         BIT1,                //3,3月
  237.         BIT0,                //4,4月
  238.         BIT7,                //5,5月
  239.         BIT6,                //6,6月
  240.         BIT5,                //7,7月
  241.         BIT4,                //8,8月
  242.         BIT3,                //9,9月
  243.         BIT2,                //10,10月
  244.         BIT1,                //11,11月
  245.         BIT0,                //12,12月
  246.         BIT7,                //13,13月
  247. };
复制代码
  1. //******************************************************************
  2. //函数名称:unsigned char Get_Lunar_Month_Days(unsigned char Lunar_Month, unsigned int Offset)
  3. //函数功能:用于读取数据表中农历月的大月或小月
  4. //输入参数:Lunar_Month,Offset
  5. //返回值:  0/1(1:大月;0:小月)
  6. //******************************************************************
  7. unsigned char Get_Lunar_Month_Days(unsigned char Lunar_Month, unsigned int Offset)
  8. {
  9.         unsigned char        Month_Long_Short;        //大小月


  10.         Month_Long_Short = 0;        //无效数据返回小月

  11.         if(Lunar_Month <= Ubound(Month_Long_Short_Bit_Table))
  12.         {
  13.                 if(Lunar_Month <= 4)        //农历参数表格第0字节bit[3:0]表示农历第1-4月的大小
  14.                 {
  15.                         Month_Long_Short = (Lunar_Year_Code[Offset].Byte_0.Bits.Month_1_4_Long_Short & Month_Long_Short_Bit_Table[Lunar_Month]);
  16.                 }
  17.                 else if(Lunar_Month <= 12)        //农历参数表格第1字节bit[7:0]表示农历第5-12月的大小
  18.                 {
  19.                         Month_Long_Short = (Lunar_Year_Code[Offset].Month_5_12_Long_Short & Month_Long_Short_Bit_Table[Lunar_Month]);
  20.                 }
  21.                 else        //农历第13个月大小
  22.                 {
  23.                         Month_Long_Short = Lunar_Year_Code[Offset].Byte_2.Bits.Month_13_Long_Short;
  24.                 }
  25.         }

  26.         if(Month_Long_Short)
  27.         {
  28.                 Month_Long_Short = 1;
  29.         }

  30.         return Month_Long_Short;
  31. }
复制代码
  1. //******************************************************************
  2. //函数名称:Solar2Lunar_Typedef Get_China_Calendar(unsigned int Year,unsigned char Month,unsigned char Day)
  3. //函数功能:公农历转换
  4. //输入参数:Year:公历年(只允许1901-2099年)  Month:公历月  Day:公历日
  5. //返回值:  0/1 1对应转换成功,0对应转换失败
  6. //******************************************************************
  7. #define        C_SOLAR_YEAR_MIN        1901                        //公历年最小值
  8. #define        C_SOLAR_YEAR_MAX        2099                        //公历年最大值

  9. Solar2Lunar_Typedef Get_China_Calendar(unsigned int Year,unsigned char Month,unsigned char Day)
  10. {
  11.         unsigned char        Spring_Festival_Month;                //当年春节所在的公历月份
  12.         unsigned char        Spring_Festival_Date;                //当年春节所在的公历日
  13.         unsigned char        Leap_Month_Flag;                //闰月,农历月不+1
  14.         unsigned char        Lunar_Month;                        //农历月
  15.         unsigned char        Lunar_Month_Temp;                //农历月(尝试判断月份)
  16.         unsigned char        Lunar_Month_Save;                //农历月保存(用于判断是不是闰月)
  17.         unsigned char        Lunar_Date;                        //农历日
  18.         unsigned char        Lunar_Leap_Month;                //闰月
  19.         unsigned char        Lunar_Month_Days;                //农历月天数
  20.         unsigned char        Spring_Festival_Days;                //当年春年离当年元旦的天数
  21.         unsigned int        Days_After_New_Years_Day;        //公历日离当年元旦的天数
  22.         unsigned int        Days_Differ;                        //两个日期天数差
  23.         unsigned int        Table_Offset;                        //农历特征数据表格查表偏移量
  24.         Solar2Lunar_Typedef Return_Value;        //返回值


  25.         Return_Value.Month = 0;                //月
  26.         Return_Value.IS_Leap_Month = 0;        //闰月标志
  27.         Return_Value.Reserved_Bits = 0;
  28.         Return_Value.Date = 0;                //日

  29.         if((Year >= C_SOLAR_YEAR_MIN) && (Year <= C_SOLAR_YEAR_MAX))        //1901~2099年之外不处理
  30.         {
  31.                 Lunar_Month_Save=0;                //农历月保存(用于判断是不是闰月)
  32.         
  33.                 /* 定位数据表地址 */
  34.                 Table_Offset = (Year - 1900);        //农历特征数据从1900年开始,但只能转换1901年之后的数据,转换春节前的数据需要前一年的数据
  35.         
  36.                 /* 取当年春节所在的公历月份 */
  37.                 Spring_Festival_Month = Lunar_Year_Code[Table_Offset].Byte_2.Bits.Spring_Festival_Month;
  38.         
  39.                 /* 取当年春节所在的公历日 */
  40.                 Spring_Festival_Date = Lunar_Year_Code[Table_Offset].Byte_2.Bits.Spring_Festival_Date;
  41.         
  42.                 /* 计算当年春年离当年元旦的天数,春节只会在公历1月或2月 */
  43.                 if ( Spring_Festival_Month == 1 )
  44.                 {
  45.                         Spring_Festival_Days = Spring_Festival_Date - 1;
  46.                 }
  47.                 else
  48.                 {
  49.                         Spring_Festival_Days = Spring_Festival_Date + 31 - 1;
  50.                 }
  51.         
  52.                 /* 计算公历日离当年元旦的天数 */
  53.                 Days_After_New_Years_Day = Days_Code[Month] + Day - 1;
  54.         
  55.                 /* 如果公历月大于2月并且该年的2月为闰月,天数加1 */
  56.                 if (Month > 2)
  57.                 {
  58.                         if((Year % 100) == 0)        //能被100整除
  59.                         {
  60.                                 if((Year % 400) == 0)        //能被400整除--闰年
  61.                                 {
  62.                                         Days_After_New_Years_Day ++;
  63.                                 }
  64.                         }
  65.                         else if (Year % 4 == 0)        //不能被100整除,能被4整除--闰年
  66.                         {
  67.                                 Days_After_New_Years_Day ++;
  68.                         }
  69.                 }
  70.         
  71.                 /* 判断公历日在春节前还是春节后 */
  72.                 if(Days_After_New_Years_Day >= Spring_Festival_Days)        //当前公历日在春节后
  73.                 {
  74.                         Days_Differ = (Days_After_New_Years_Day - Spring_Festival_Days);        //Days_Differ存放当前公历日距离当前春节公历日天数
  75.                         
  76.                         Lunar_Month = 1;                //农历月
  77.                         Lunar_Month_Temp = 1;                //农历月,从1月开始判断(第一个月不会是闰月,直接农历正月天数)
  78.                         Leap_Month_Flag = 0;                //闰月,农历月不+1
  79.         
  80.                         if(Get_Lunar_Month_Days(Lunar_Month_Temp, Table_Offset) == 0)        //农历月天数
  81.                         {
  82.                                 Lunar_Month_Days = 29;        /* 小月29天 */
  83.                         }
  84.                         else
  85.                         {
  86.                                 Lunar_Month_Days = 30;        /* 大月30天 */
  87.                         }
  88.         
  89.                         /* 从数据表中取该年的闰月月份,如为0则该年无闰月 */
  90.                         Lunar_Leap_Month = Lunar_Year_Code[Table_Offset].Byte_0.Bits.Leap_Month;
  91.         
  92.                         while(Days_Differ >= Lunar_Month_Days)        //天数差>=当前处理农历月天数
  93.                         {
  94.                                 Days_Differ -= Lunar_Month_Days;
  95.                                 
  96.                                 if(Lunar_Month == Lunar_Leap_Month)        //农历月=当年农历闰月
  97.                                 {
  98.                                         Leap_Month_Flag = (~Leap_Month_Flag);        //闰月标志
  99.                                        
  100.                                         if (Leap_Month_Flag == 0)
  101.                                         {
  102.                                                 Lunar_Month ++;        //闰月之后的下一个月
  103.                                         }
  104.                                         else
  105.                                         {
  106.                                                 Lunar_Month_Save = Lunar_Month;        //农历月保存(用于判断是不是闰月)
  107.                                         }
  108.                                 }
  109.                                 else
  110.                                 {
  111.                                         Lunar_Month ++;                //下一个月
  112.                                 }
  113.                                 
  114.                                 Lunar_Month_Temp ++;
  115.         
  116.                                 if(Get_Lunar_Month_Days(Lunar_Month_Temp, Table_Offset) == 0)
  117.                                 {
  118.                                         Lunar_Month_Days = 29;
  119.                                 }
  120.                                 else
  121.                                 {
  122.                                         Lunar_Month_Days = 30;
  123.                                 }
  124.                         }
  125.         
  126.                         Lunar_Date = (Days_Differ + 1);                //农历日
  127.                 }
  128.                 else        /* 公历日在春节前使用下面代码进行运算 */
  129.                 {
  130.                         Days_Differ = (Spring_Festival_Days - Days_After_New_Years_Day);
  131.                         
  132.                         Table_Offset -= 1;        //未到当年春节,取前一年的农历特征表格
  133.                         Lunar_Month = 12;        //从前一年农历十二月开始判断
  134.                         
  135.                         Lunar_Leap_Month = Lunar_Year_Code[Table_Offset].Byte_0.Bits.Leap_Month;        //闰月月份
  136.                         
  137.                         if (Lunar_Leap_Month == 0)        //当前年没有闰月
  138.                         {
  139.                                 Lunar_Month_Temp = 12;        //农历月,从12月开始判断
  140.                         }
  141.                         else
  142.                         {
  143.                                 Lunar_Month_Temp = 13;        //农历月,当前年有闰月,从13月开始判断
  144.                         }
  145.         
  146.                         Leap_Month_Flag = 0;        //闰月,农历月不-1
  147.         
  148.                         if(Get_Lunar_Month_Days(Lunar_Month_Temp, Table_Offset) == 0)        //农历月天数
  149.                         {
  150.                                 Lunar_Month_Days = 29;        /* 小月29天 */
  151.                         }
  152.                         else
  153.                         {
  154.                                 Lunar_Month_Days = 30;        /* 大月30天 */
  155.                         }
  156.         
  157.                         while(Days_Differ > Lunar_Month_Days)
  158.                         {
  159.                                 Days_Differ -= Lunar_Month_Days;
  160.                                 
  161.                                 Lunar_Month_Temp --;
  162.                                 
  163.                                 if(Leap_Month_Flag == 0)
  164.                                 {
  165.                                         Lunar_Month --;
  166.                                 }
  167.                                 
  168.                                 if(Lunar_Month == Lunar_Leap_Month)
  169.                                 {
  170.                                         Leap_Month_Flag = (~Leap_Month_Flag);
  171.                                        
  172.                                         if(Leap_Month_Flag)
  173.                                         {
  174.                                                 Lunar_Month_Save = Lunar_Month;        //农历月保存(用于判断是不是闰月)
  175.                                         }
  176.                                 }
  177.                                 
  178.                                 if(Get_Lunar_Month_Days(Lunar_Month_Temp, Table_Offset) == 0)
  179.                                 {
  180.                                         Lunar_Month_Days = 29;
  181.                                 }
  182.                                 else
  183.                                 {
  184.                                         Lunar_Month_Days = 30;
  185.                                 }
  186.                         }
  187.         
  188.                         Lunar_Date = (Lunar_Month_Days - Days_Differ + 1);        //农历日
  189.                 }
  190.         
  191.                 if(Lunar_Month == Lunar_Month_Save)        //当前月=闰月保存月份
  192.                 {
  193.                         Return_Value.IS_Leap_Month = 1;        //闰月标志=1
  194.                 }
  195.                
  196.                 Return_Value.Month = Lunar_Month;        //保存转换农历月、日
  197.                 Return_Value.Date = Lunar_Date;
  198.         }

  199.         return        Return_Value;        //返回值
  200. }
复制代码

转换实例:
(1)定义一个结构体变量保存转换返回值
  1. Solar2Lunar_Typedef Lunar_Data;        //公历转农历返回值
复制代码
(2)简单判断数据是否有效(待转换日期在预设范围内都会返回有效结果)。
  1.         Lunar_Data=Get_China_Calendar(Year,Month,Date);        //公历转农历
  2.         
  3.         if(Lunar_Data.Month != 0)        //数据有效
  4.         {
  5.                 Lunar_Calendar.Month = Lunar_Data.Month;        //保存转换农历月、日
  6.                 Lunar_Calendar.Date= Lunar_Data.Date;
  7.                
  8.                 Lunar_Calendar.IS_Leap_Month = Lunar_Data.IS_Leap_Month;        //闰月标志
  9.         }
复制代码



打赏

参与人数 3家元 +90 收起 理由
hefanghua + 30 这是最详尽的了!果断收藏。
水表君 + 30 優秀文章
兔包公 + 30 以資鼓勵

查看全部打赏

发表于 2025-6-24 11:25:15 | 显示全部楼层
感谢楼主的分享,正需要。
回复 支持 反对

使用道具 举报

发表于 2025-5-23 16:08:26 | 显示全部楼层
留个印记,网上好多农历查表数组都是错的
回复 支持 反对

使用道具 举报

发表于 2025-5-1 07:04:20 | 显示全部楼层
不好意思,是我弄错了。请教楼主,只想用2000到2099年的数据。应该怎样修改
回复 支持 反对

使用道具 举报

发表于 2025-4-30 16:13:17 | 显示全部楼层
本帖最后由 lmn2005 于 2025-4-30 16:36 编辑

不知道日出和日落有没有什么公式可以计算






补充:找到了,不过还没有下载下来应证
  https://gitcode.com/Universal-To ... &type=card&

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2025-4-29 13:10:38 | 显示全部楼层
mmxx2015 发表于 2025-4-29 12:18
如果只管今年的农历,把这行改了就行了:
改为:

已经修改,好了!谢谢!
顺便也把其他几个年份错误的也改了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-4-29 12:18:29 | 显示全部楼层
lmn2005 发表于 2025-4-29 11:54
我从网上下载的公历转农历h文件(忘记了从哪里下载的),这个月的农历又错了。
今天是四月初二,而转换出来 ...

如果只管今年的农历,把这行改了就行了:
  1. 0x69,0x57,0x3d, //2025
复制代码
改为:
  1. 0x6A,0x57,0x3d, //2025
复制代码


回复 支持 反对

使用道具 举报

发表于 2025-4-29 11:54:03 | 显示全部楼层
本帖最后由 lmn2005 于 2025-4-29 11:56 编辑

我从网上下载的公历转农历h文件(忘记了从哪里下载的),这个月的农历又错了。
今天是四月初二,而转换出来的是四月初三
表内数据是这样的:
  1. uchar code Data[]={

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


回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-4-28 21:27:29 | 显示全部楼层
dujq 发表于 2025-4-28 15:29
楼主这个日期出错 公历: 2057-10-5 农历: 9月7日 9月8日 9月7日

你用在哪个单片机平台?我用在STC 51单片机、小华ARM M0+单片机,转换结果都是正确的。

日梭万年历2057-10-5的农历日期是九月初八


用在STC8H4K64TL的转换结果


用在HC32L196KCTA的转换结果

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2025-4-28 15:29:59 | 显示全部楼层
楼主这个日期出错 公历: 2057-10-5 农历: 9月7日 9月8日 9月7日
回复 支持 反对

使用道具 举报

发表于 2025-2-22 23:41:13 | 显示全部楼层
这个很有用,参考程序
回复 支持 反对

使用道具 举报

发表于 2025-2-17 16:48:19 | 显示全部楼层
确实遇到这种情况。感谢楼主分享!留个脚印。
回复 支持 反对

使用道具 举报

发表于 2025-2-7 00:35:43 | 显示全部楼层
好东西,收藏了,改天有空也搞-搞
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-2-4 10:49:24 | 显示全部楼层
水表君 发表于 2025-2-3 23:09
网上看到好多类似的转换程序,关于“农历计算”的程序不计其数,甚至有的人做出小工具来生成代码。不过都是 ...

看过日梭万年历网络版、寿星天文历的源码,农历、节气、干支是可以计算的,只是计算方法很复杂,计算量很大,大部分单片机难以完成。
要生成大量日历数据,可以参考这两个日历程序算法在电脑上编程生成,也可以简单编程修改电脑日期再调用这两个程序得到。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2025-2-3 23:09:34 | 显示全部楼层
网上看到好多类似的转换程序,关于“农历计算”的程序不计其数,甚至有的人做出小工具来生成代码。不过都是查表法,也正因为查表法就带来很大的不确定性,之前我也用过好多程序都出现过一些日期错误问题,所以这类的程序主要难点我觉得在于验证的准确性!折腾过几次也懒得去折腾了,现在基本上都在玩ESP32和ESP8266,对于农历,节气这些直接API获取,还省的出错自己去修。我曾经也想过把这些农历常用的查询信息,比如农历日期,二十四节气,天干,地支等等都封装成一个库,然后不断更新,奈何也是被这种验证问题磨没了毅力。看楼主发言就是一个对中国农历有很深厚的研究的人,如果楼主有毅力,有时间,可以做个开源库,让全中国玩编程的都用你的库,能做到统一管理,我想到这种程度就能到100%准确性了!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-29 17:44:19 | 显示全部楼层
本帖最后由 mmxx2015 于 2025-2-4 11:03 编辑

13楼的干支年转换程序有问题,应改为以立春日为界。
不过,大部分的日历还是以正月初一作为干支年、生肖年的分界,还有的干支年以正月初一为界、生肖年以立春日为界。


修正后的程序:
  1. //******************************************************************
  2. //函数名称:unsigned char Get_24_Solar_Terms(unsigned int Year,unsigned char Month,unsigned char Day)
  3. //函数功能:查询当天是不是二十四节气之一
  4. //输入参数:Year:公历年(只允许1901-2099年)  Month:公历月  Day:公历日
  5. //返回值:  0xff:不是;0~23:24节气编号(0-小寒,1-大寒,2-立春 …… 23冬至)
  6. //******************************************************************
  7. unsigned char Get_24_Solar_Terms(unsigned int Year,unsigned char Month,unsigned char Day)
  8. {
  9.         unsigned char        Solar_Terms_Data;
  10.         unsigned char        Solar_Terms_Day;
  11.         unsigned char        Return_Value;                //返回值
  12.         
  13.         
  14.         Return_Value = 0xff;        //默认返回无效值
  15.         
  16.         if((Year >= C_SOLAR_YEAR_MIN) && (Year <= C_SOLAR_YEAR_MAX))        //公历年范围
  17.         {        
  18.                 Solar_Terms_Data = Solar_Terms_Code[(Year - C_SOLAR_YEAR_MIN)][(Month - 1)];        //当月24节气的公历日期编码
  19.                
  20.                 if(Day < 15)        //高4位,当月第一个节气
  21.                 {
  22.                         Solar_Terms_Day = (15 - (Solar_Terms_Data >> 4));
  23.                         if(Day == Solar_Terms_Day)
  24.                         {
  25.                                 Return_Value = ((Month - 1) * 2);
  26.                         }
  27.                 }
  28.                 else        //低4位,当月第二个节气
  29.                 {
  30.                         Solar_Terms_Day = (15 + (Solar_Terms_Data & 0x0f));
  31.                         if(Day == Solar_Terms_Day)
  32.                         {
  33.                                 Return_Value = (((Month - 1) * 2) + 1);
  34.                         }
  35.                 }
  36.         }
  37.         
  38.         return        Return_Value;        //返回值
  39. }


  40. //******************************************************************
  41. //函数名称:unsigned char Get_Heavenly_Stems_Earthly_Branches(unsigned int Year,unsigned char Month,unsigned char Date)
  42. //函数功能:查询当年天干地支序数
  43. //输入参数:Year:公历年(需≥1864年 && ≤(1864+255)年),月,日
  44. //返回值:bit[7:4]天干序数+bit[3:0]地支序数(其中0xFF表示无效值)
  45. //******************************************************************
  46. unsigned char Get_Heavenly_Stems_Earthly_Branches(unsigned int Year,unsigned char Month,unsigned char Date)
  47. {
  48.         unsigned int        Table_Offset;                        //农历特征数据表格查表偏移量
  49.         unsigned char        The_Beginning_Of_Spring_Date;        //立春日对应的公历日期
  50.         unsigned char        Year_Differ;                        //输入年份与指定甲子年年份差
  51.         unsigned char        Year_Remainder;                        //(Year_Differ % 60)
  52.         unsigned char        Return_Value;                        //返回值:天干序数+地支序数
  53.         
  54.         
  55.         Return_Value = 0xff;        //默认返回无效值
  56.         
  57.         if((Year >= C_SOLAR_YEAR_MIN) && (Year <= C_SOLAR_YEAR_MAX))        //有24节气公历日期表格年范围
  58.         {
  59.                 if((Year >= C_SEXAGENARY_YEAR) && (Year <= (C_SEXAGENARY_YEAR + 255)))        //可计算公历年范围
  60.                 {
  61.                         Year_Differ = (Year - C_SEXAGENARY_YEAR);        //输入年份与指定甲子年年份差
  62.                         
  63.                         //干支纪年和生肖年以立春日为界;立春是公历2月第1个节气
  64.                         if(Month == 1)        //未到立春日
  65.                         {
  66.                                 if(Year == C_SEXAGENARY_YEAR)        //指定甲子年立春日之前
  67.                                 {
  68.                                         Return_Value = (((10 - 1) <<4) | (12-1));        //返回癸亥年
  69.                                        
  70.                                         return        Return_Value;        //返回值
  71.                                 }
  72.                                 else
  73.                                 {
  74.                                         Year_Differ --;        //年份差 - 1
  75.                                 }
  76.                         }               
  77.                         else if((Month == 2) && (Date < 15))        //指定公历日期在立春前还是后(立春日的公历日期不会超过2月15日)
  78.                         {
  79.                                 /* 定位数据表地址 */
  80.                                 Table_Offset = (Year - C_SOLAR_YEAR_MIN);        //二十四节气特征数据从1901年开始
  81.                                 
  82.                                 /* 取当年立春日所的公历日期(立春是公历2月第1个节气) */
  83.                                 The_Beginning_Of_Spring_Date = (15 - (Solar_Terms_Code[Table_Offset][1] >> 4));
  84.                                 
  85.                                 if(Date < The_Beginning_Of_Spring_Date)        //未到立春日
  86.                                 {
  87.                                         if(Year == C_SEXAGENARY_YEAR)        //指定甲子年立春日之前
  88.                                         {
  89.                                                 Return_Value = (((10 - 1) <<4) | (12-1));        //返回癸亥年
  90.                                        
  91.                                                 return        Return_Value;        //返回值
  92.                                         }
  93.                                         else
  94.                                         {
  95.                                                 Year_Differ --;        //年份差 - 1
  96.                                         }
  97.                                 }
  98.                         }
  99.                         
  100.                         Year_Remainder = (Year_Differ % 60);                //60年一个周期
  101.                         
  102.                         Return_Value = ((Year_Remainder % 10) << 4);        //天干序数
  103.                         Return_Value |= (Year_Remainder % 12);                //地支序数
  104.                 }
  105.         }
  106.         
  107.         return        Return_Value;        //返回值
  108. }
复制代码

回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 19:22:55 | 显示全部楼层
本帖最后由 mmxx2015 于 2025-1-23 19:30 编辑
hydize 发表于 2025-1-23 17:43
看了下代码,感觉是不是有点复杂了?我是直接以公元0年庚申年为基准,这样只要年份直接对10、12取余就得到 ...

年份直接除以10、12得到干支数确实少了一些计算,如果是51单片机,可能计算量差不多,因为年份除以10、12都是16位除以8位计算,不能直接硬件计算,年份减起始年份1864的差值不超过255,只需做8位除法,可以硬件一次完成计算。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 19:09:06 | 显示全部楼层
hydize 发表于 2025-1-23 17:28
从另外一个帖子过来的,的确有几个年份的农历数据是错误的。我用的节气数据只到2050年,前几天下载了个香港 ...

查表转换速度快,也比较省电,一般“万年历”的年份范围从1901~2099年,数据量不大。
回复 支持 反对

使用道具 举报

发表于 2025-1-23 17:43:19 | 显示全部楼层
天干地支编年转换:根据百度知道回复编写程序....

看了下代码,感觉是不是有点复杂了?我是直接以公元0年庚申年为基准,这样只要年份直接对10、12取余就得到天干、地址的序列了。
当然这个0年是不存在的,实际就是公元前一年了。就是为了省事,但天干地支的顺序得按庚申开头来排序了,后续月日时的干支也需要同样的顺序。
回复 支持 反对

使用道具 举报

发表于 2025-1-23 17:28:03 | 显示全部楼层
从另外一个帖子过来的,的确有几个年份的农历数据是错误的。我用的节气数据只到2050年,前几天下载了个香港天文台的数据,自己又整理的。对照楼主修正的,还好整理的基本都对。
关于星期计算,我一直都是在用基姆拉尔森公式算的,不过我的用处是在电纸屏显示,所以速度快慢都好像影响不大。
回复 支持 反对

使用道具 举报

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

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-20 03:50 , Processed in 0.670802 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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