1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Text.RegularExpressions;
6: using System.Globalization;
7:
8: namespace AnkeEdu.Tools
9: {
10: /// <summary>
11: /// 中国日历信息实体类
12: ///
13: /// </summary>
14: public sealed class ChineseCalendar
15: {
16: private DateTime m_SolarDate;
17: private int m_LunarYear, m_LunarMonth, m_LunarDay;
18: private bool m_IsLeapMonth = false;
19: private string m_LunarYearSexagenary = null, m_LunarYearAnimal = null;
20: private string m_LunarYearText = null, m_LunarMonthText = null, m_LunarDayText = null;
21: private string m_SolarWeekText = null, m_SolarConstellation = null, m_SolarBirthStone = null;
22:
23: #region 构造函数
24:
25: public ChineseCalendar()
26: : this(DateTime.Now.Date)
27: {
28:
29: }
30:
31: /// <summary>
32: /// 从指定的阳历日期创建中国日历信息实体类
33: /// </summary>
34: /// <param name="date">指定的阳历日期</param>
35: public ChineseCalendar(DateTime date)
36: {
37: m_SolarDate = date;
38: LoadFromSolarDate();
39: }
40:
41: private void LoadFromSolarDate()
42: {
43: m_IsLeapMonth = false;
44: m_LunarYearSexagenary = null;
45: m_LunarYearAnimal = null;
46: m_LunarYearText = null;
47: m_LunarMonthText = null;
48: m_LunarDayText = null;
49: m_SolarWeekText = null;
50: m_SolarConstellation = null;
51: m_SolarBirthStone = null;
52:
53: m_LunarYear = calendar.GetYear(m_SolarDate);
54: m_LunarMonth = calendar.GetMonth(m_SolarDate);
55: int leapMonth = calendar.GetLeapMonth(m_LunarYear);
56:
57: if (leapMonth == m_LunarMonth)
58: {
59: m_IsLeapMonth = true;
60: m_LunarMonth -= 1;
61: }
62: else if (leapMonth > 0 && leapMonth < m_LunarMonth)
63: {
64: m_LunarMonth -= 1;
65: }
66:
67: m_LunarDay = calendar.GetDayOfMonth(m_SolarDate);
68:
69: CalcConstellation(m_SolarDate, out m_SolarConstellation, out m_SolarBirthStone);
70: }
71:
72: #endregion
73:
74: #region 日历属性
75:
76: /// <summary>
77: /// 阳历日期
78: /// </summary>
79: public DateTime SolarDate
80: {
81: get { return m_SolarDate; }
82: set
83: {
84: if (m_SolarDate.Equals(value))
85: return;
86: m_SolarDate = value;
87: LoadFromSolarDate();
88: }
89: }
90: /// <summary>
91: /// 星期几
92: /// </summary>
93: public string SolarWeekText
94: {
95: get
96: {
97: if (string.IsNullOrEmpty(m_SolarWeekText))
98: {
99: int i = (int)m_SolarDate.DayOfWeek;
100: m_SolarWeekText = ChineseWeekName[i];
101: }
102: return m_SolarWeekText;
103: }
104: }
105: /// <summary>
106: /// 阳历星座
107: /// </summary>
108: public string SolarConstellation
109: {
110: get { return m_SolarConstellation; }
111: }
112: /// <summary>
113: /// 阳历诞生石
114: /// </summary>
115: public string SolarBirthStone
116: {
117: get { return m_SolarBirthStone; }
118: }
119:
120: /// <summary>
121: /// 阴历年份
122: /// </summary>
123: public int LunarYear
124: {
125: get { return m_LunarYear; }
126: }
127: /// <summary>
128: /// 阴历月份
129: /// </summary>
130: public int LunarMonth
131: {
132: get { return m_LunarMonth; }
133: }
134: /// <summary>
135: /// 是否阴历闰月
136: /// </summary>
137: public bool IsLeapMonth
138: {
139: get { return m_IsLeapMonth; }
140: }
141: /// <summary>
142: /// 阴历月中日期
143: /// </summary>
144: public int LunarDay
145: {
146: get { return m_LunarDay; }
147: }
148:
149: /// <summary>
150: /// 阴历年干支
151: /// </summary>
152: public string LunarYearSexagenary
153: {
154: get
155: {
156: if (string.IsNullOrEmpty(m_LunarYearSexagenary))
157: {
158: int y = calendar.GetSexagenaryYear(this.SolarDate);
159: m_LunarYearSexagenary = CelestialStem.Substring((y - 1) % 10, 1) + TerrestrialBranch.Substring((y - 1) % 12, 1);
160: }
161: return m_LunarYearSexagenary;
162: }
163: }
164: /// <summary>
165: /// 阴历年生肖
166: /// </summary>
167: public string LunarYearAnimal
168: {
169: get
170: {
171: if (string.IsNullOrEmpty(m_LunarYearAnimal))
172: {
173: int y = calendar.GetSexagenaryYear(this.SolarDate);
174: m_LunarYearAnimal = Animals.Substring((y - 1) % 12, 1);
175: }
176: return m_LunarYearAnimal;
177: }
178: }
179:
180:
181: /// <summary>
182: /// 阴历年文本
183: /// </summary>
184: public string LunarYearText
185: {
186: get
187: {
188: if (string.IsNullOrEmpty(m_LunarYearText))
189: {
190: m_LunarYearText = Animals.Substring(calendar.GetSexagenaryYear(new DateTime(m_LunarYear, 1, 1)) % 12 - 1, 1);
191: StringBuilder sb = new StringBuilder();
192: int year = this.LunarYear;
193: int d;
194: do
195: {
196: d = year % 10;
197: sb.Insert(0, ChineseNumber[d]);
198: year = year / 10;
199: } while (year > 0);
200: m_LunarYearText = sb.ToString();
201: }
202: return m_LunarYearText;
203: }
204: }
205: /// <summary>
206: /// 阴历月文本
207: /// </summary>
208: public string LunarMonthText
209: {
210: get
211: {
212: if (string.IsNullOrEmpty(m_LunarMonthText))
213: {
214: m_LunarMonthText = (this.IsLeapMonth ? "闰" : "") + ChineseMonthName[this.LunarMonth - 1];
215: }
216: return m_LunarMonthText;
217: }
218: }
219:
220: /// <summary>
221: /// 阴历月中日期文本
222: /// </summary>
223: public string LunarDayText
224: {
225: get
226: {
227: if (string.IsNullOrEmpty(m_LunarDayText))
228: m_LunarDayText = ChineseDayName[this.LunarDay - 1];
229: return m_LunarDayText;
230: }
231: }
232:
233: #endregion
234:
235: /// <summary>
236: /// 根据指定阳历日期计算星座&诞生石
237: /// </summary>
238: /// <param name="date">指定阳历日期</param>
239: /// <param name="constellation">星座</param>
240: /// <param name="birthstone">诞生石</param>
241: public static void CalcConstellation(DateTime date, out string constellation, out string birthstone)
242: {
243: int i = Convert.ToInt32(date.ToString("MMdd"));
244: int j;
245: if (i >= 321 && i <= 419)
246: j = 0;
247: else if (i >= 420 && i <= 520)
248: j = 1;
249: else if (i >= 521 && i <= 621)
250: j = 2;
251: else if (i >= 622 && i <= 722)
252: j = 3;
253: else if (i >= 723 && i <= 822)
254: j = 4;
255: else if (i >= 823 && i <= 922)
256: j = 5;
257: else if (i >= 923 && i <= 1023)
258: j = 6;
259: else if (i >= 1024 && i <= 1121)
260: j = 7;
261: else if (i >= 1122 && i <= 1221)
262: j = 8;
263: else if (i >= 1222 || i <= 119)
264: j = 9;
265: else if (i >= 120 && i <= 218)
266: j = 10;
267: else if (i >= 219 && i <= 320)
268: j = 11;
269: else
270: {
271: constellation = "未知星座";
272: birthstone = "未知诞生石";
273: return;
274: }
275: constellation = Constellations[j];
276: birthstone = BirthStones[j];
277:
278: #region 星座划分
279: //白羊座: 3月21日------4月19日 诞生石: 钻石
280: //金牛座: 4月20日------5月20日 诞生石: 蓝宝石
281: //双子座: 5月21日------6月21日 诞生石: 玛瑙
282: //巨蟹座: 6月22日------7月22日 诞生石: 珍珠
283: //狮子座: 7月23日------8月22日 诞生石: 红宝石
284: //处女座: 8月23日------9月22日 诞生石: 红条纹玛瑙
285: //天秤座: 9月23日------10月23日 诞生石: 蓝宝石
286: //天蝎座: 10月24日-----11月21日 诞生石: 猫眼石
287: //射手座: 11月22日-----12月21日 诞生石: 黄宝石
288: //摩羯座: 12月22日-----1月19日 诞生石: 土耳其玉
289: //水瓶座: 1月20日-----2月18日 诞生石: 紫水晶
290: //双鱼座: 2月19日------3月20日 诞生石: 月长石,血石
291: #endregion
292: }
293:
294:
295: #region 阴历转阳历
296:
297: /// <summary>
298: /// 获取指定年份春节当日(正月初一)的阳历日期
299: /// </summary>
300: /// <param name="year">指定的年份</param>
301: public static DateTime GetLunarNewYearDate(int year)
302: {
303: DateTime dt = new DateTime(year, 1, 1);
304: int cnYear = calendar.GetYear(dt);
305: int cnMonth = calendar.GetMonth(dt);
306:
307: int num1 = 0;
308: int num2 = calendar.IsLeapYear(cnYear) ? 13 : 12;
309:
310: while (num2 >= cnMonth)
311: {
312: num1 += calendar.GetDaysInMonth(cnYear, num2--);
313: }
314:
315: num1 = num1 - calendar.GetDayOfMonth(dt) + 1;
316: return dt.AddDays(num1);
317: }
318:
319: /// <summary>
320: /// 阴历转阳历
321: /// </summary>
322: /// <param name="year">阴历年</param>
323: /// <param name="month">阴历月</param>
324: /// <param name="day">阴历日</param>
325: /// <param name="IsLeapMonth">是否闰月</param>
326: public static DateTime GetDateFromLunarDate(int year, int month, int day, bool IsLeapMonth)
327: {
328: if (year < 1902 || year > 2100)
329: throw new Exception("只支持1902~2100期间的农历年");
330: if (month < 1 || month > 12)
331: throw new Exception("表示月份的数字必须在1~12之间");
332:
333: if (day < 1 || day > calendar.GetDaysInMonth(year, month))
334: throw new Exception("农历日期输入有误");
335:
336: int num1 = 0, num2 = 0;
337: int leapMonth = calendar.GetLeapMonth(year);
338:
339: if (((leapMonth == month + 1) && IsLeapMonth) || (leapMonth > 0 && leapMonth <= month))
340: num2 = month;
341: else
342: num2 = month - 1;
343:
344: while (num2 > 0)
345: {
346: num1 += calendar.GetDaysInMonth(year, num2--);
347: }
348:
349: DateTime dt = GetLunarNewYearDate(year);
350: return dt.AddDays(num1 + day - 1);
351: }
352:
353: /// <summary>
354: /// 阴历转阳历
355: /// </summary>
356: /// <param name="date">阴历日期</param>
357: /// <param name="IsLeapMonth">是否闰月</param>
358: public static DateTime GetDateFromLunarDate(DateTime date, bool IsLeapMonth)
359: {
360: return GetDateFromLunarDate(date.Year, date.Month, date.Day, IsLeapMonth);
361: }
362:
363: #endregion
364:
365: #region 从阴历创建日历
366:
367: /// <summary>
368: /// 从阴历创建日历实体
369: /// </summary>
370: /// <param name="year">阴历年</param>
371: /// <param name="month">阴历月</param>
372: /// <param name="day">阴历日</param>
373: /// <param name="IsLeapMonth">是否闰月</param>
374: public static ChineseCalendar FromLunarDate(int year, int month, int day, bool IsLeapMonth)
375: {
376: DateTime dt = GetDateFromLunarDate(year, month, day, IsLeapMonth);
377: return new ChineseCalendar(dt);
378: }
379: /// <summary>
380: /// 从阴历创建日历实体
381: /// </summary>
382: /// <param name="date">阴历日期</param>
383: /// <param name="IsLeapMonth">是否闰月</param>
384: public static ChineseCalendar FromLunarDate(DateTime date, bool IsLeapMonth)
385: {
386: return FromLunarDate(date.Year, date.Month, date.Day, IsLeapMonth);
387: }
388:
389: /// <summary>
390: /// 从阴历创建日历实体
391: /// </summary>
392: /// <param name="date">表示阴历日期的8位数字,例如:20070209</param>
393: /// <param name="IsLeapMonth">是否闰月</param>
394: public static ChineseCalendar FromLunarDate(string date, bool IsLeapMonth)
395: {
396: Regex rg = new System.Text.RegularExpressions.Regex(@"^\d{7}(\d)$");
397: Match mc = rg.Match(date);
398: if (!mc.Success)
399: {
400: throw new Exception("日期字符串输入有误!");
401: }
402: DateTime dt = DateTime.Parse(string.Format("{0}-{1}-{2}", date.Substring(0, 4), date.Substring(4, 2), date.Substring(6, 2)));
403: return FromLunarDate(dt, IsLeapMonth);
404: }
405:
406:
407: #endregion
408:
409: private static ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
410: public const string ChineseNumber = "〇一二三四五六七八九";
411: public const string CelestialStem = "甲乙丙丁戊己庚辛壬癸";
412: public const string TerrestrialBranch = "子丑寅卯辰巳午未申酉戌亥";
413: public const string Animals = "鼠牛虎兔龙蛇马羊猴鸡狗猪";
414: public static readonly string[] ChineseWeekName = new string[] { "星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
415: public static readonly string[] ChineseDayName = new string[] {
416: "初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
417: "十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
418: "廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"};
419: public static readonly string[] ChineseMonthName = new string[] { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
420: public static readonly string[] Constellations = new string[] { "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座" };
421: public static readonly string[] BirthStones = new string[] { "钻石", "蓝宝石", "玛瑙", "珍珠", "红宝石", "红条纹玛瑙", "蓝宝石", "猫眼石", "黄宝石", "土耳其玉", "紫水晶", "月长石,血石" };
422:
423:
424:
425: }
426: }