知识大全 NET Framework2.0中的农历类

Posted 农历

篇首语:停下休息的时候,不要忘记别人还在奔跑。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 NET Framework2.0中的农历类相关的知识,希望对你有一定的参考价值。

NET Framework2.0中的农历类  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  一 简介

  过年是中国(以及日本 韩国等国)人民的第一大节日 你怎么知道哪天过年?查日历或者听别人说?程序员当然有程序员的办法 就是写程序啦

  虽然公历(俗称的 阳历 )已经成了全世界的通用标准 而且也具有多方面的优越性 但在东亚地区 还是离不开 农历 春节 元宵 端午 中秋 重阳这些节日是农历的 大部份人的老爸老妈的生日也是农历的

  早在 框架出来的时候 我就认为微软公司不应该 厚彼薄此 框架中提供了希伯来历等 却没有提供更广泛使用的 农历

  而 中 微软公司终于做出了这个小小的改进

   在System Globalization命名空间中新增加了EastAsianLunisolarCalendar 类及以继承它的ChineseLunisolarCalendar JapaneseLunisolarCalendar KoreanLunisolarCalendar TaiwanLunisolarCalendar等几个类 LunisolarCalendar顾名思义应为 阴阳历 我的理解是因为我们所用的农历虽然按照月亮公转来编月份 但用 闰月 的方式来调整年份与地球公转的误差 严格意义上来说是结合了月亮公转和地球公转的成份 因此属于 阴阳历 但我这里还是按照习惯称之为 农历

  二 新的农历类还是没有公民待遇

  为了测试新的日历类 我兴冲冲地写了几句代码 (省略了调用这个方法的其它代码)

  运行报错 错误信息是 Not a valid calendar for the given culture

  为了说明问题 继续测试

  可以正常运行 结果是 年x月x日(民国纪年) 注释掉中间那条语句 结果是 年x月x日(也就是使用公历) 将中间那条语句修改成 ci DateTimeFormat Calendar = new TaiwanLunisolarCalendar() 照样出错 查相关资料 原来DateTimeFormat的Calendar属性只能为CultureInfo的OptionalCalendars属性所指定范围

  于是再写一段代码测试OptionalCalendars的内容 对于zh CN语言 惟一可用于日期格式的calendar是本地化的GregorianCalendar(也就是公历) 对于zh 可用于日期格式的calendar是美国英语和本地化的GregorianCalendar以及TaiwanCalendar(即公历的年份减 ) 都没有包括农历

  也就是 虽然提供了农历类 但对它的支持并不及同样有闰月的希伯来历 我查资料的时候找到了博客堂的一篇文章<; 作者在一年半以前发现了农历类不支持日期格式化的问题 并认为这是一个bug 当然还算不上bug 只不过微软没有重视而已(责任在微软吗?我想应该不是 在商业社会我们有多重视微软就会有多重视 和以色列比起来 我们对传统文化的重视程度差得太远)

  三 农历类的使用

  既框架不支持直接将日期转换成农历格式的字符串 那么要将显示农历格式的日期 就只要自已写代码了 不过由于已经有了ChineseLunisolarCalendar类实现了公历转换为农历日期的功能 所以要写这样的代码也比较简单 需要用到ChineseLunisolarCalendar以下几个主要方法

  int GetYear (DateTime time) 获取指定公历日期的农历年份 使用的还是公历纪元 在每年的元旦之后春节之前农历的纪年会比公历小 其它时候等于公历纪年 虽然农历使用传说中的耶稣生日纪元似乎不太妥当 不过我们确实已经几十年没有实行一个更好的纪年办法 也只有将就了

  int GetMonth (DateTime time) 获取指定公历日期的农历月份 这里要注意了 由于农历有接近三分之一的年份存在闰月 则在这些年份里会有十三个 而具体哪一个月是闰月也说不准 这里不同于希伯来历 以今年为例 今年闰七月 则此方法在参数为闰七月的日期是返回值为 参数为农历十二月的日期时返回值为

  bool IsLeapMonth ( int year    int month) 获取指定农历年份和月份是否为闰月 这个函数和上个函数配合使用就可以算出农历的月份了

  int GetDayOfMonth (DateTime time) 获取指定公历日期的农历天数 这个值根据大月或者小月取值是 到 或者 到 MSDN上说的 到 显然是错的 没有哪个农历月份会有 天

  int GetSexagenaryYear (DateTime time) 获取指定公历日期的农历年份的干支纪年 从 到 分别是甲子 乙丑 丙寅 … 癸亥 比如戊戌变法 辛亥革命就是按这个来命名的 当然算八字也少不了这个

  int GetCelestialStem (int sexagenaryYear) 获取一个天支的天干 从 到 表示甲 乙 丙… 说白了就是对 取模

  int GetTerrestrialBranch (int sexagenaryYear) ) 获取一个干支的地支 从 到 表示子 丑 寅 …今年是狗年 那么今年年份的地支就是 戌

  有了这几个方法 显示某天的农历月份日期 农历节日等都是小菜一碟 算命先生排八字用这几个方法 又快又准确 写出的代码也很短

  四 几种东亚农历类的区别

  经过我的测试 ChineseLunisolarCalendar JapaneseLunisolarCalendar KoreanLunisolaCalendarr TaiwanLunisolarCalendar这四种日历 无论哪一种 以 年 月 日为参数 调用它们的GetMonth方法得到的结果都是 GetDayOfMonth得到的结果都是 想想也是 我们过的端午节和韩国的不太可能不是一天

  但是调用GetYear方法得到结果就有区别了ChineseLunisolarCalendar和KoreanLunisolarCalendar都返回 也就是公历纪年 TaiwanLunisolarCalendar的返回值是 依然是民国纪年 JapaneseLunisolarCalendar的返回值是 平成纪年

  另外的一个区别是这四种日历的MinSupportedDateTime和MaxSupportedDateTime各不一样 以下是对照表

  日历类MinSupportedDateTimeMaxSupportedDateTime

  ChineseLunisolarCalendar公元 年 月初 公元 年 月

  TaiwanLunisolarCalendar民国 年 月初 民国 年 月

  JapaneseLunisolarCalendar昭和 年 月初 平成 年 月

  KoreanLunisolarCalendar公元 年 月初 公元 年 月

  韩国农历类支持的最小日期为 年(也即高丽王朝建立的年份) 以此而论 中国农历类支持的最小日期不说从商周算起 从汉唐算总该没问题吧?微软公司啊 又在 厚彼薄此 唉

  其次 日本还以天皇纪年 如果哪天xxxx 岂不是使用JapaneseLunisolarCalendar写出的程序都有问题啦?

  五 写自已的日期格式化器

  昨天看了一篇文章 说目前大家用的 农历 这个术语是文革时期才有的 目的是反封建 这里为了省事 还是继续使用这个术语 而英文名称ChineseLunisolarCalendar太长 我自己的代码中就用ChineseCalendar为相关功能命名 这个名字也还过得去吧

  我原先设想自定义一个类 使得能写出这样的代码

  string s= DateTime Now ToString(new MyFormatProvider());

  虽然不能为DataTime写自定义的格式器 但还有另外一个途径 就是为String类的Format方法写自定义格式化器 我测试了一下 效果还不错 调用方式如下

  string s= String Format(new ChineseCalendarFormatter() :D DateTime Now);

  可以得到 二〇〇六年正月初九

  string s= String Format(new ChineseCalendarFormatter() :d DateTime Now);

  可以得到 丙戌年正月初九

  虽然没有前面所设想的方便 但也还能接受 全部代码帖出如下

  第一个类 主要是封装了农历的一些常用字符和对日历处理的最基本功能

  就能得出我想要的农历日期字符串 经过测试却失败了 依据我的分析 微软公司框架中把日期时间型的格式写死了 只能依据相关的地区采用固定的几种显示格式 没法再自行定义 而前文已经说过 而所有的相关格式微软公司都放到一个名为culture nlp的文件中(这个文件在以前框架是一个独立的文件 被作为一个资源编译到mscorlib dll中 ) (我的这个不能为DateTime写自已的格式化器的观点没有资料佐证 如有不当之处 请大家指正)

  ChineseCalendarHelper cs

  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 % ;

  sb Insert( ChineseNumber[d]);

  year = year / ;

   while (year > );

  return sb ToString();

  

  public static string GetMonth(DateTime time)

  

  int month = calendar GetMonth(time);

  int year = calendar GetYear(time);

  int leap = ;

  //正月不可能闰月

  for (int i = ; i <= month; i++)

  

  if (calendar IsLeapMonth(year i))

  

  leap = i;

  break;  //一年中最多有一个闰月

  

  

  if (leap > ) month ;

  return (leap == month + ? 闰 : ) + ChineseMonthName[month ];

  

  public static string GetDay(DateTime time)

  

  return ChineseDayName[calendar GetDayOfMonth(time) ];

  

  public static string GetStemBranch(DateTime time)

  

  int sexagenaryYear = calendar GetSexagenaryYear(time);

  string stemBranch = CelestialStem Substring(sexagenaryYear % ) + TerrestrialBranch Substring(sexagenaryYear % );

  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[] 正 二 三 四 五 六 七 八 九 十 十一 十二 ;

  

  第二个类为自定义格式化器

  ChineseCalendarFormatter cs

  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( 年 月

  ChineseCalendarHelper GetYear(time)

  ChineseCalendarHelper GetMonth(time)

  ChineseCalendarHelper GetDay(time));

  break;

  case d : //短日期格式

  s = String Format( 年 月 ChineseCalendarHelper GetStemBranch(time)

  ChineseCalendarHelper GetMonth(time)

  ChineseCalendarHelper GetDay(time));

  break;

  case M : //月日格式

  s = String Format( 月 ChineseCalendarHelper GetMonth(time)

  ChineseCalendarHelper GetDay(time));

  break;

  case Y : //年月格式

  s = String Format( 年 月 ChineseCalendarHelper GetYear(time)

  ChineseCalendarHelper GetMonth(time));

  break;

  default:

  s = String Format( 年 月 ChineseCalendarHelper GetYear(time)

  ChineseCalendarHelper GetMonth(time)

  ChineseCalendarHelper GetDay(time));

  break;

  

  

  return s;

  

  

  这段代码中间处理格式那部份稍做改进 就可以支持更多的日期格式

  有了这两段代码为原型 要实现计算和显示一个日期的农历日期及其它功能 基本上就很容易了

  实现

  private string getDateString(DateTime dt)

  

  CultureInfo ci = new CultureInfo( zh );

  ci DateTimeFormat Calendar = new TaiwanCalendar();

  return dt ToString( D ci);

  

  private string getDateString(DateTime dt)

  

  CultureInfo ci = new CultureInfo( zh CN );

  ci DateTimeFormat Calendar = new ChineseLunisolarCalendar();

  return dt ToString( D ci);

cha138/Article/program/ASP/201311/21710

相关参考

知识大全 用ASP.Net中的自带类进行MD5加密

用ASP.Net中的自带类进行MD5加密  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 用反射调用任意.net库中的方法

注:ReturnMessage是我自写的一个类作用请查看我的其他文章我也把这个类一并附在后面通过NameSpaceAndClassName和MethodName实际上就可以精确定位一个方法了如调用ab

知识大全 c#中国农历时间类

  原来还准备自己写算法并研究农历规则发现那太难和麻烦了光是农历的推算那就我等专门研究历法的人一下搞懂的后来发现NET类库也提供一些基础的农历类SystemGlobalizationChineseLu

知识大全 VB.NET中的模块

VB.NET中的模块  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在C#中有静态类的概念自然里

知识大全 .NET中的特殊类型成员[3]

.NET中的特殊类型成员[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  索引属性  某些类

知识大全 .net的编程之路(一)

  一预定义数据类型  char字符类型单引号例如charx=this;  c#中的每个数据类型其实就是一个静态的类每个变量都是一个类的实例  例如将int型的数据转化为stringstringx=i

知识大全 .NET框架类小结

.NET框架类小结  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一基本概念  NET框架(Fr

知识大全 .net程序员应该掌握的常用类库

  系统类  Type类Object类String类Array类Console类Exception类GC类MarshalByRefObject类Math类  DateTime结构Guid结构  ICl

知识大全 Net框架类库中定时器类的使用

Net框架类库中定时器类的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  不论在客户端应用程

知识大全 .Net框架类库中定时器类的使用[1]

技巧:.Net框架类库中定时器类的使用[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  不论