筆記-顯示民國年與閏年蟲
6 |
昨天是四年才出現一次的2/29,也是未滿四歲系統的小關卡,結果在網路上跟生活周遭還真目賭不少程式跌倒~~
最常見的狀況是該顯示民國年的地方出現101/2/28而非101/2/29,究其根源,多半是當初程式在撰寫時使用了DateTime.Today.AddYears(-1911).ToString("yyyy/MM/dd")的簡便寫法,乍看之下比單獨抓出年份額外處理簡潔許多,卻隱藏了閏年判定基準不同的問題(民國101年是西元2012年為閏年,但減去1911為西元101年變成非閏年;另外若需要計算星期幾,這種計算方法也會出錯,只是會立即被揪出來),因此這隻閏年蟲就躲在一些2008/3/1日之後才寫好的系統中,通過測試完成驗收,正確無誤地運作多年,到第一次遇上2/29才揭竿而起(若剛好是假日,說不定還能再躲四年),攪亂一池春水。
以下我整理了幾種顯示民國年日期的寫法: (比起來都不如AddYears(-1911)做法來得簡潔,難怪許多人會誤用這個看起來很漂亮其實有毒的寫法)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DateTime d = new DateTime(2012, 2, 29);
//幾種顯示民國年的方法
//1.另外取年減1911
Console.WriteLine(
string.Format("民國{0}年{1:MM月dd日}",
d.Year - 1911, d)
);
//2.借用TaiwanCalender
//(沒想到.NET Library中有這個吧!! 微軟就甘心A)
System.Globalization.TaiwanCalendar tc
= new System.Globalization.TaiwanCalendar();
Console.WriteLine(
"{0}/{1:MM/dd}", tc.GetYear(d), d);
//同場加映,另外有TaiwanLunisolarCalendar可以查農曆哦!
//可惜目前還不支援看吉凶沖煞,無法得知否宜嫁娶動土上樑(大誤)
System.Globalization.TaiwanLunisolarCalendar tlc =
new System.Globalization.TaiwanLunisolarCalendar();
Console.WriteLine("農曆: {0}年{1}月{2}日",
tlc.GetYear(d), tlc.GetMonth(d), tlc.GetDayOfMonth(d));
//3.借用demo寫的擴充方法http://demo.tc/Post/579
Console.WriteLine(d.ToTaiwanCalendar("yyyy/MM/dd"));
Console.Read();
}
}
static class DateExt
{
/// <summary>
/// 轉換為民國年
/// </summary>
///<param name="format">標準格式化語法</param>
/// <returns></returns>
static public string ToTaiwanCalendar(this DateTime x, string format)
{
DateTime now = x;
TaiwanCalendar tc = new TaiwanCalendar();
Regex regex = new System.Text.RegularExpressions.Regex(@"[yY]+");
format = regex.Replace(format, tc.GetYear(x).ToString("000"));
return x.ToString(format);
}
}
}
執行結果:
民國101年02月29日
101/02/29
農曆: 101年2月8日
101/02/29
今天學到的教訓:
- 遇到系統規格中民國年轉換時,記得針對2/29 進行測試
- 看到簡潔寫法時,採用前記得推敲是否隱含邏輯瑕疵,顏色鮮豔的蘑菇往往有毒呀~
- 手邊如有運作未滿四年還沒上幼稚園中班的新系統,第一次碰到閏年時記得要提高警覺
- 3/1起,應該還是會有民國閏年蟲陸續被新同學埋進新系統裡,通過測試驗收等待2016/2/29來臨 XD
Comments
# by 風箏
前輩 關於農曆的判定有BUG,會有閏月問題 需要再套用GetLeapMonth來判定指定年度的閏月數另在處理才不會出現異常
# by 風箏
前輩 關於農曆的判定有BUG,會有閏月問題 需要再套用GetLeapMonth來判定指定年度的閏月數另在處理才不會出現異常
# by demo
意外看到自己的玩意XD 同場加映一下,寫成 d.ToTaiwanCalendar("民國yy年MM月dd日") 會更好用哩
# by Jeffrey
to 風箏, 謝謝提醒,原來還需要額外的邏輯處理閏月問題,稍後會再補充。
# by jain
我們之前也是遇到閏月問題,所以不敢用, 沒想到用GetLeapMonth可以解決, 謝謝風箏大。
# by .
微軟也出槌... http://blogs.msdn.com/b/windowsazure/archive/2012/03/09/summary-of-windows-azure-service-disruption-on-feb-29th-2012.aspx