筆記-顯示民國年與閏年蟲

昨天是四年才出現一次的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

今天學到的教訓:

  1. 遇到系統規格中民國年轉換時,記得針對2/29 進行測試
  2. 看到簡潔寫法時,採用前記得推敲是否隱含邏輯瑕疵,顏色觧豔的蘑菇往往有毒呀~
  3. 手邊如有運作未滿四年還沒上幼稚園中班的新系統,第一次碰到閏年時記得要提高警覺
  4. 3/1起,應該還是會有民國閏年蟲陸續被新同學埋進新系統裡,通過測試驗收等待2016/2/29來臨 XD
歡迎推文分享:
Published 01 March 2012 06:09 AM 由 Jeffrey
Filed under: ,
Views: 17,153



意見

# 風箏 said on 29 February, 2012 09:51 PM

前輩

關於農曆的判定有BUG,會有閏月問題

需要再套用GetLeapMonth來判定指定年度的閏月數另在處理才不會出現異常

# 風箏 said on 29 February, 2012 09:53 PM

前輩

關於農曆的判定有BUG,會有閏月問題

需要再套用GetLeapMonth來判定指定年度的閏月數另在處理才不會出現異常

# demo said on 29 February, 2012 10:38 PM

意外看到自己的玩意XD

同場加映一下,寫成

d.ToTaiwanCalendar("民國yy年MM月dd日")

會更好用哩

# Jeffrey said on 29 February, 2012 11:52 PM

to 風箏, 謝謝提醒,原來還需要額外的邏輯處理閏月問題,稍後會再補充。

# jain said on 01 March, 2012 08:07 AM

我們之前也是遇到閏月問題,所以不敢用,

沒想到用GetLeapMonth可以解決,

謝謝風箏大。

# . said on 13 March, 2012 08:59 PM

微軟也出槌...

blogs.msdn.com/.../summary-of-windows-azure-service-disruption-on-feb-29th-2012.aspx

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<March 2012>
SunMonTueWedThuFriSat
26272829123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication