五、写自已的日期格式化器
第二个类为自定义格式化器:
有了这两段代码为原型,要实现计算和显示一个日期的农历日期及其它功能,基本上就很容易了。
昨天看了一篇文章,说目前大家用的“农历”这个术语是文革时期才有的,目的是反封建。这里为了省事,还是继续使用这个术语。而英文名称ChineseLunisolarCalendar太长,我自己的代码中就用ChineseCalendar为相关功能命名,这个名字也还过得去吧。
我原先设想自定义一个类,使得能写出这样的代码:
string s= DateTime.Now.ToString(new MyFormatProvider());
就能得出我想要的农历日期字符串,经过测试却失败了,依据我的分析,微软公司在.net框架中把日期时间型的格式写死了,只能依据相关的地区采用固定的几种显示格式,没法再自行定义。而前文已经说过,而所有的相关格式微软公司都放到一个名为culture.nlp的文件中(这个文件在以前的.net框架是一个独立的文件,在.net 2.0被作为一个资源编译到mscorlib.dll中。) (我的这个不能为DateTime写自已的格式化器的观点没有资料佐证,如有不当之处,请大家指正)
虽然不能为DataTime写自定义的格式器,但还有另外一个途径,就是为String类的Format方法写自定义格式化器,我测试了一下,效果还不错,调用方式如下:
string s= String.Format(new ChineseCalendarFormatter(), "{0:D}",DateTime.Now);
可以得到“二〇〇六年正月初九”
string s= String.Format(new ChineseCalendarFormatter(), "{0:d}",DateTime.Now);
可以得到“丙戌年正月初九”
虽然没有前面所设想的方便,但也还能接受,全部代码帖出如下:
第一个类,主要是封装了农历的一些常用字符和对日历处理的最基本功能
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
public static class ChineseCalendarHelper
{
public static string GetYear(DateTime time)
{
StringBuilder sb = new StringBuilder();
int year = calendar.GetYear(time);
int d;
do
{
d = year % 10;
sb.Insert(0, ChineseNumber[d]);
year = year / 10;
} while (year > 0);
return sb.ToString();
}
public static string GetMonth(DateTime time)
{
int month = calendar.GetMonth(time);
int year = calendar.GetYear(time);
int leap = 0;
//正月不可能闰月
for (int i = 3; i <= month; i++)
{
if (calendar.IsLeapMonth(year, i))
{
leap = i;
break; //一年中最多有一个闰月
}
}
if (leap > 0) month--;
return (leap == month + 1 ? "闰" : "") + ChineseMonthName[month - 1];
}
public static string GetDay(DateTime time)
{
return ChineseDayName[calendar.GetDayOfMonth(time) - 1];
}
public static string GetStemBranch(DateTime time)
{
int sexagenaryYear = calendar.GetSexagenaryYear(time);
string stemBranch = CelestialStem.Substring(sexagenaryYear % 10 - 1, 1) +
TerrestrialBranch.Substring(sexagenaryYear % 12 - 1, 1);
return stemBranch;
}
private static ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
private static string ChineseNumber = "〇一二三四五六七八九";
public const string CelestialStem = "甲乙丙丁戊己庚辛壬癸";
public const string TerrestrialBranch = "子丑寅卯辰巳午未申酉戌亥";
public static readonly string[] ChineseDayName = new string[] {
"初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
"十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
"廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"};
public static readonly string[] ChineseMonthName = new string[]
{ "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
}
using System.Collections.Generic;
using System.Text;
using System.Globalization;
public static class ChineseCalendarHelper
{
public static string GetYear(DateTime time)
{
StringBuilder sb = new StringBuilder();
int year = calendar.GetYear(time);
int d;
do
{
d = year % 10;
sb.Insert(0, ChineseNumber[d]);
year = year / 10;
} while (year > 0);
return sb.ToString();
}
public static string GetMonth(DateTime time)
{
int month = calendar.GetMonth(time);
int year = calendar.GetYear(time);
int leap = 0;
//正月不可能闰月
for (int i = 3; i <= month; i++)
{
if (calendar.IsLeapMonth(year, i))
{
leap = i;
break; //一年中最多有一个闰月
}
}
if (leap > 0) month--;
return (leap == month + 1 ? "闰" : "") + ChineseMonthName[month - 1];
}
public static string GetDay(DateTime time)
{
return ChineseDayName[calendar.GetDayOfMonth(time) - 1];
}
public static string GetStemBranch(DateTime time)
{
int sexagenaryYear = calendar.GetSexagenaryYear(time);
string stemBranch = CelestialStem.Substring(sexagenaryYear % 10 - 1, 1) +
TerrestrialBranch.Substring(sexagenaryYear % 12 - 1, 1);
return stemBranch;
}
private static ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
private static string ChineseNumber = "〇一二三四五六七八九";
public const string CelestialStem = "甲乙丙丁戊己庚辛壬癸";
public const string TerrestrialBranch = "子丑寅卯辰巳午未申酉戌亥";
public static readonly string[] ChineseDayName = new string[] {
"初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
"十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
"廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"};
public static readonly string[] ChineseMonthName = new string[]
{ "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
}
第二个类为自定义格式化器:
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Threading;
public class ChineseCalendarFormatter : IFormatProvider, ICustomFormatter
{
//实现IFormatProvider
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return Thread.CurrentThread.CurrentCulture.GetFormat(formatType);
}
//实现ICustomFormatter
public string Format(string format, object arg, IFormatProvider formatProvider)
{
string s;
IFormattable formattable = arg as IFormattable;
if (formattable == null)
s = arg.ToString();
else
s = formattable.ToString(format, formatProvider);
if (arg.GetType() == typeof(DateTime))
{
DateTime time = (DateTime)arg;
switch (format)
{
case "D": //长日期格式
s = String.Format("{0}年{1}月{2}",
ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "d": //短日期格式
s = String.Format("{0}年{1}月{2}", ChineseCalendarHelper.GetStemBranch(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "M": //月日格式
s = String.Format("{0}月{1}", ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "Y": //年月格式
s = String.Format("{0}年{1}月", ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time));
break;
default:
s = String.Format("{0}年{1}月{2}", ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
}
}
return s;
}
}
这段代码中间处理格式那部份稍做改进,就可以支持更多的日期格式。using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Threading;
public class ChineseCalendarFormatter : IFormatProvider, ICustomFormatter
{
//实现IFormatProvider
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return Thread.CurrentThread.CurrentCulture.GetFormat(formatType);
}
//实现ICustomFormatter
public string Format(string format, object arg, IFormatProvider formatProvider)
{
string s;
IFormattable formattable = arg as IFormattable;
if (formattable == null)
s = arg.ToString();
else
s = formattable.ToString(format, formatProvider);
if (arg.GetType() == typeof(DateTime))
{
DateTime time = (DateTime)arg;
switch (format)
{
case "D": //长日期格式
s = String.Format("{0}年{1}月{2}",
ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "d": //短日期格式
s = String.Format("{0}年{1}月{2}", ChineseCalendarHelper.GetStemBranch(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "M": //月日格式
s = String.Format("{0}月{1}", ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
case "Y": //年月格式
s = String.Format("{0}年{1}月", ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time));
break;
default:
s = String.Format("{0}年{1}月{2}", ChineseCalendarHelper.GetYear(time),
ChineseCalendarHelper.GetMonth(time),
ChineseCalendarHelper.GetDay(time));
break;
}
}
return s;
}
}
有了这两段代码为原型,要实现计算和显示一个日期的农历日期及其它功能,基本上就很容易了。