網頁

2014年6月4日 星期三

基本題 - C# 西元年轉換取得民國年格式字串

在台灣使用 .NET Framework C# 的開發人員對於這樣的轉換都應該內化為基本操作知識,也就是當有西元年轉為民國年的需求時,都要能夠馬上使用正確的方式來取得正確的資料內容,而並不是直接使用減去 1911 的方式來結案。

為什麼呢?

你使用任何一個閏年(台灣每次總統大選年、夏季奧運舉辦年、美國總統就職的那一年)去取得 2 月 29 日,然後直接用減去 1911 的方式來看結果,我想大部分的人就會知道答案了,如果你還是不懂,那就繼續看下去。

 


以下是使用 LINQPad 來做示範(或是你也可以使用 CShell,或是也可以使用線上的 .NET Fiddle 來操作)

建立一個 2012.02.29 的日期,然後直接使用減去 1911 的方式來取得民國年,下圖的執行結果裡原本應該是民國 101 年 2 月 29 日卻變成了 28 日,這就是為什麼不要用西元年減去 1911 的方式來取得民國年的原因。

image

或許有人會說也才這麼一天會出問題,以特例的方式做處理不就好了…

有以上想法的朋友,如果你才接觸程式開發沒多久的話,那……還有救,觀念趕快導正過來就好,如果你已經是資深(或是名片上、職稱上號稱的)程式開發人員,我必須語重心長的告訴你「快點 BR 吧」。

如果你覺得只要將月份與日期單獨取出然後將年份單獨減去 1911 的話,這做法也行,只不過這方法治標不治本。

 

System.Globalization.TaiwanCalendar

應該要怎麼做才能正確的從西元年轉換取得民國年呢?

請使用 TaiwanCalendar 類別

http://msdn.microsoft.com/zh-tw/library/system.globalization.taiwancalendar

所以上面的程式就應該使用 TaiwanCalendar 來處理,如下:

image

 

擴充方法

覺得每次要從西元年轉換取得民國年很麻煩的話,那就直接做成擴充方法,這樣就可以地把西元年轉換為民國年,

image

public static class DateTimeExtensions
{
   /// <summary>
   /// To the full taiwan date.
   /// </summary>
   /// <param name="datetime">The datetime.</param>
   /// <returns></returns>
   public static string ToFullTaiwanDate(this DateTime datetime)
   {
       TaiwanCalendar taiwanCalendar = new TaiwanCalendar();
 
       return string.Format("民國 {0} 年 {1} 月 {2} 日", 
           taiwanCalendar.GetYear(datetime),
           datetime.Month, 
           datetime.Day);
   }
 
   /// <summary>
   /// To the simple taiwan date.
   /// </summary>
   /// <param name="datetime">The datetime.</param>
   /// <returns></returns>
   public static string ToSimpleTaiwanDate(this DateTime datetime)
   {
       TaiwanCalendar taiwanCalendar = new TaiwanCalendar();
 
       return string.Format("{0}/{1}/{2}",
           taiwanCalendar.GetYear(datetime),
           datetime.Month,
           datetime.Day);
   }
}

執行結果

image

 

.NET Fiddle 線上直接預覽

https://dotnetfiddle.net/TIOFdG

 

如果你想要在取得民國年格式字串的時候傳入自定義的字串格式,那麼可以參考 demo 的作法:

擴充 DateTime 轉換顯示民國年 | demo小鋪

 

西元年轉換取得民國年的問題每隔四年就會在 Google 成為熱門搜尋的焦點,這是存在已久而且是老掉牙的題目了,除了台灣之外,還有許多國家也是有不同的曆法換算問題,所以都要特別注意。

 

台灣農民曆

農民曆的作法比較特別,要使用另一個曆法的類別「TaiwanLunisolarCalendar

MSDN - TaiwanLunisolarCalendar 類別

農民曆的算法相當特殊,農曆不像一般西元年有閏年,但是卻有閏月,例如閏五月、閏八月,還有其他一些特別的地方需要注意,不過會需要處理農曆的機會並不多,但還是要特別注意,以下內容來自於 MSDN 說明,

TaiwanLunisolarCalendar 類別衍生自 EastAsianLunisolarCalendar 類別,表示陰曆。 EastAsianLunisolarCalendar 類別除了陽曆年和陰曆月份之外,也支援 60 年為一週期的農曆年。 此曆法中的每一個陽曆年都會有關聯的農曆年 (六十年為一週期)、天干和地支,而且這些曆法可以在一年的任何月份之後多加閏月。
閏月可能發生在一年當中的任何一個月份之後。 例如,EastAsianLunisolarCalendar.GetMonth(DateTime) 方法傳回介於 1 與 13 之間的數字,指出與指定日期關聯的月份。 如果一年當中的第八個月到第九個月之間有閏月,GetMonth 方法會傳回 8,代表第八個月,傳回 9 代表閏八月,然後傳回 10 代表第九個月。
目前,CultureInfo 類別 (Class) 支援的任何文化特性 (Culture) 都未使用 TaiwanLunisolarCalendar。 因此,這個類別只可以用來計算台灣陰陽曆的日期。
每一個 CultureInfo 物件都支援一套曆法。 Calendar 屬性傳回預設文化特性 (Culture) 的曆法,而 OptionalCalendars 屬性則傳回陣列,其包含文化特性所支援的所有曆法。 若要變更 CultureInfo 所使用的日曆,應用程式就必須將 CultureInfo.DateTimeFormat 的 Calendar 屬性設定為新的 Calendar。

有關農民曆的處理,可以參考以下連結內的作法,

TaiwanLunisolarCalendar 拿農曆日期的方法(包含生肖天干地支顯示) - Python_NoteBook

 


延伸閱讀:

筆記-顯示民國年與閏年蟲 - 黑暗執行緒

[C#] DateTime輸出民國年 - 愛流浪的小風- 點部落

 

相關連結

[C#][VB.NET]西元轉民國 - 小歐ou | 菜鳥自救會- 點部落

 

以上

沒有留言:

張貼留言