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 | 菜鳥自救會- 點部落

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。