本文介绍如何使用ChineseLunisolarCalendar类获取农历日期信息。
ChineseLunisolarCalendar类定义在System.Globalization命名空间,常用的方法包括:
为方便使用,我们在cfx/CnDate.cs文件中封装CnDate类,下面的代码是类中包含的字段和数据数组。
using System; using System.Globalization; namespace cfx { public class CnDate { protected DateTime myDate; protected int myCnYear; protected int myCnMonth; protected int myCnDay; protected int myLeapMonth; protected int myTianGan; protected int myDiZhi; // 十天干 protected static string[] tianGan = {" ", "甲","乙","丙","丁","戊","己","庚","辛","壬","癸" }; // 十二地支 protected static string[] diZhi = { " ","子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}; // 生肖 protected static string[] shengXiao = { " ","鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"}; // 月份名称 protected static string[] cnMonth = {"","正月","二月","三月","四月","五月","六月", "七月","八月","九月","十月","冬月","腊月"}; // protected static string[] cnDay = { "","初一","初二","初三","初四","初五" ,"初六","初七","初八","初九","初十" ,"十一","十二","十三","十四","十五" ,"十六","十七","十八","十九","二十" ,"廿一","廿二","廿三","廿四","廿五" ,"廿六","廿七","廿八","廿九","三十" }; } }
其中的字段包括:
tianGan数组,定义了十天干的名称,请注意,数组的第一个元素为空,这么是为了通过索引快速对应1到10的天干名称,以下的数组也都是这样。
diZhi数组,定义十二地支的名称。
shengXiao数组,十二地支对应的生肖名称,即属相名称。
cnMonth数组,农历月份的基本名称。
cnDay数组,农历日子的名称。
接下来,会在构造函数中计算DateTime数据对应的农历信息,如下面的代码。
// public CnDate(DateTime dt) { ChineseLunisolarCalendar cale = new ChineseLunisolarCalendar(); myDate = dt; // 农历年份,甲子年份 myCnYear = cale.GetSexagenaryYear(myDate); // 天干 myTianGan = cale.GetCelestialStem(myCnYear); // 地支 myDiZhi = cale.GetTerrestrialBranch(myCnYear); // 农历月份 myCnMonth = cale.GetMonth(myDate); // 农历闰月 if (myDate.Month < 3 && myCnMonth > 9) myLeapMonth = cale.GetLeapMonth(myDate.Year - 1); else myLeapMonth = cale.GetLeapMonth(myDate.Year); // 农历月中第几天 myCnDay = cale.GetDayOfMonth(myDate); } // public CnDate() : this(DateTime.Now) { } // public CnDate(int year, int month, int day) : this(new DateTime(year, month, day)) { }
代码中共有三个版本的构造函数,第一个构造函数包含了农历信息的计算方法,需要一个DateTime类型的参数,其中,大部分信息直接通过ChineseLunisolarCalendar类的方法获取即可,需要特别注意闰月的计算,当公历为一月或二月,而农历为冬月或腊月,使用GetLeapMonth()方法返回闰月时,参数应设置为公历的前一年。
接下来的两个构造函数都会调用第一个版本,没有设置参数时,会使用系统的当前时间;最后一个构造函数可以通过公历的年、月、日设置日期信息。
得到农历的数值信息后,可以使用方法或只读属性返回对应的文本信息,如下面的代码。
// public string YearName { get { return tianGan[myTianGan] + diZhi[myDiZhi]; } } // public string MonthName { get { if (myLeapMonth > 0) { if (myCnMonth < myLeapMonth) return cnMonth[myCnMonth]; else if (myCnMonth == myLeapMonth) return "闰" + cnMonth[myCnMonth - 1]; else return cnMonth[myCnMonth - 1]; } else { return cnMonth[myCnMonth]; } } } // public string DayName { get { return cnDay[myCnDay]; } } // public string ShengXiao { get { return shengXiao[myDiZhi]; } } // new public string ToString() { return string.Format("农历 {0}({1})年 {2}{3}", YearName, ShengXiao, MonthName, DayName); }
代码中,YearName只读属性会通过天干和地支组成农历年份名称。
MonthName只读属性中需要注意闰月的情况,农历当年包含闰月时,myLeapMonth会大于0,此时,当前月小于myLeapMonth时直接返回对应的月份名称;当前月等于myLeapMonth时表示为闰月,月份基本名称是myLeapMonth减1对应的名称,需要在月份名称前添加“闰”字;当前月大于myLeapMonth时,使用当前月数值减1,并返回对应的月份名称。农历当年没有闰月时,直接返回对应的月份名称即可。
DayName只读属性,从cnDay数组返回对应的日子名称。
ShengXiao只读属性,从shengXiao数组返回对应的生肖名称。
ToString()方法,返回完整的农历日期信息,可以根据需要修改显示内容和格式。
下面的代码,在Program.cs文件中测试CnDate类的应用。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { CnDate cd = new CnDate(2026,7,19); Console.WriteLine(cd.YearName); Console.WriteLine(cd.MonthName); Console.WriteLine(cd.DayName); Console.WriteLine(cd.ShengXiao); Console.WriteLine(cd.ToString()); } } }
代码中,指定公历日期为2026年7月19日,显示的信息如下图所示。
农历日期中还可以添加一些其它功能,如判断农历节日,下面的代码会使用GetFestival()方法返回一些常见的农历节日。
// 返回非闰月的真实月份 protected int GetRealMonth() { if (myLeapMonth > 0) { if (myCnMonth < myLeapMonth) return myCnMonth; else return myCnMonth - 1; } else { return myCnMonth; } } // 返回农历节日 public string GetFestival() { int m = GetRealMonth(), d = myCnDay; if (m == 1 && d == 1) return "春节"; else if (m == 1 && d == 15) return "元宵节"; else if (m == 5 && d == 5) return "端午节"; else if (m == 8 && d == 15) return "中秋节"; // 除夕 CnDate nextDay = new CnDate(myDate.AddDays(1)); if (nextDay.myCnMonth == 1 && nextDay.myCnDay == 1) return "除夕"; // return ""; }
代码中,GetRealMonth()方法会返回实际的月份值,不包括闰月月份。GetFestival()方法中则会根据实际的月份和日子判断节日,如正月初一为春节、正月十五为元宵节、五月初五为端午节、八月十五为中秋节;这里需要注意除夕的判断,因为腊月可能有29天或30天,也就是说除夕未必就是大年三十,但有一点是肯定的,除夕过后就是正月初一,代码中也是根据这一逻辑判断。
下面的代码,在Program.cs文件中测试GetFestival()方法的应用。
using System; using cfx; namespace csfx_demo { class Program { static void Main(string[] args) { CnDate cd = new CnDate(2026,6,19); Console.WriteLine(cd.GetFestival()); } } }
执行代码会显示“端午节”。