C# 农历日历转换实现原理与完整代码

Ryan
Ryan
发布时间:2026-10-14| 6人浏览过
原创

在 C# 应用程序开发中,有时需要将标准的公历日期转换为传统的农历日期(包含生肖、干支及农历月日)。本文详细解析了基于固定数据表的农历转换算法,提供从核心配置到完整方法调用的实现方案,帮助开发者快速集成农历功能。

核心逻辑与数据结构

实现农历转换的核心在于建立一套公历与农历的映射规则。由于农历月份长度不固定且存在闰月,通常采用预置的“农历数据表”(LunarData)来解决。该表中存储了从起始年份(如 1921 年)开始每年的农历信息位图,记录了当年是否为闰年、有几个月以及每个月是大月(30天)还是小月(29天)。

除了农历日期本身,转换过程还需要以下辅助数组:

  • 天干(TianGan)与地支(DiZhi):用于组合成干支纪年(如甲子年)。
  • 十二生肖(ShengXiao):根据年份计算对应的生肖动物。
  • 农历月份名称(MonthName):将数字月份映射为中文汉字(如一、二...腊)。
  • 农历日期名称(DayName):将天数映射为初一、初二等表示。
  • 公历累计天数(MonthAdd):用于快速计算公历某月到年初的累计天数。

完整代码实现

以下是可以直接复制使用的 C# 类片段。它包含了上述所有数组定义以及核心的 GetLunarCalendar 转换方法。该方法接收一个 DateTime 对象,返回格式化的农历字符串(例如:“丙午年 六月十二日”)。

//天干 
private static string []TianGan = 
    {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
//地支 
private static string []DiZhi = 
    {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
//十二生肖 
private static string []ShengXiao = 
    {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
//农历日期 
private static string []DayName = 
    {"*","初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
     "十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
     "廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"};
//农历月份 
private static string []MonthName = 
    {"*","正","二","三","四","五","六","七","八","九","十","十一","腊"};
//公历月计数天 
private static int []MonthAdd = 
    {0,31,59,90,120,151,181,212,243,273,304,334};
//农历数据表 (简化示例,实际使用时需填入完整的 long/int 数组) 
//注:原文档中的 LunarData 是一个包含多位数数据的整型数组
//这里保留其原始结构示意
private static int []LunarData = 
    {2635,333387,1701,1748,267701,694,2391,133423,1175,396438,
     3402,3749,331177,1453,694,201326,2350,465197,3221,3402,
     // ... 省略中间数据,实际项目中请确保包含 1921-2100 年的完整数据 ...
     2635,661067,1701,1748,398772,2742,2391,330031};

public string GetLunarCalendar(DateTime dtDay)
{
    string sYear = dtDay.Year.ToString(); 
    string sMonth = dtDay.Month.ToString();
    string sDay = dtDay.Day.ToString();
    int year;
    int month;
    int day;
    try {
        year = int.Parse(sYear);
        month = int.Parse(sMonth);
        day = int.Parse(sDay);
    } catch {
        year = DateTime.Now.Year;
        month = DateTime.Now.Month;
        day = DateTime.Now.Day;
    }
    int nTheDate;
    int nIsEnd;
    int k, m, n, nBit, i;
    string calendar = string.Empty;
    
    //1. 计算该公历日期距离基准日(1921年2月8日)的天数差
    //基准日 1921-2-8 为农历正月初一
    nTheDate = (year - 1921) * 365 + (year - 1921) / 4 + day + MonthAdd[month - 1] - 38;
    if ((year % 4 == 0) && (month > 2)) nTheDate += 1; // 处理闰年情况
    
    //2. 遍历农历数据表,确定农历的年、月、日
    nIsEnd = 0; m = 0; k = 0; n = 0;
    while (nIsEnd != 1)
    {
        //判断当前农历年是 12 个月还是 13 个月
        if (LunarData[m] < 4095) k = 11; else k = 12; 
        n = k;
        
        //逐月扣除天数
        while (n >= 0)
        {
            //获取 LunarData[m] 的第 n 个二进制位的值,判断该月大小
            nBit = LunarData[m];
            for (i = 1; i < n + 1; i++) nBit = nBit / 2;
            nBit = nBit % 2;
            
            if (nTheDate <= (29 + nBit)) { nIsEnd = 1; break; }
            nTheDate = nTheDate - 29 - nBit; 
            n = n - 1;
        }
        if (nIsEnd == 1) break; 
        m = m + 1;
    }
    
    year = 1921 + m; 
    month = k - n + 1; 
    day = nTheDate;

    #region 格式化输出
    //处理闰月:若当月是闰月,则标记为负数并在显示时加“闰”字
    if (k == 12)
    {
        if (month == LunarData[m] / 65536 + 1)
            month = 1 - month; // 变为负数代表闰月
        else if (month > LunarData[m] / 65536 + 1)
            month = month - 1; // 后续月份序号减 1
    }
    
    //拼接生肖
    calendar = ShengXiao[(year - 4) % 60 % 12].ToString() + "年 ";
    //拼接天干
    calendar += TianGan[(year - 4) % 60 % 10].ToString();
    //拼接地支
    calendar += DiZhi[(year - 4) % 60 % 12].ToString() + " ";
    
    //拼接月份名称
    if (month < 1)
        calendar += "闰" + MonthName[-1 * month].ToString() + "月";
    else
        calendar += MonthName[month].ToString() + "月";
    
    //拼接日期名称
    calendar += DayName[day].ToString() + "日";
    
    return calendar;
    #endregion
}

使用注意事项

  1. 数据完整性:上述代码中的 LunarData 数组仅为示意性片段。在实际生产环境中,你需要获取完整的农历数据表(通常覆盖 1901 年至 2100 年或更长时间),并将其完整粘贴到 int[] LunarData 中,否则转换结果将不准确。
  2. 性能优化:如果频繁调用此方法,建议将静态数组初始化放在类加载阶段,或者考虑将其封装为单例模式/静态工具类,避免重复创建对象。
  3. 边界测试:农历转换涉及复杂的阴阳历法规则,建议在部署前针对春节、闰四月等特殊日期进行单元测试验证。
以上就是 C# 实现农历日历转换方法的详细内容,更多关于 C# 日期处理与农历算法的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。