收到一個需求,要在前一年底將隔年全年的放假日存入資料庫,原本想用政府資料開放平臺的中華民國政府行政機關辦公日曆表,看了一下格式常在改,命名規則也一直變動,因為我不想常維護這程式,俗話說,隔3年後,你寫的程式就變成別人寫的,自己也看不懂;所以放棄自動匯入一途,改為由程式產生預設假日。
臺灣的假日很多,但是放假的國定假日越來越少,所以我就存到資料庫,再設定一個欄位是否放假,以後若有變動時,直接改資料庫就好。看到這張表,想起來小時候還放過國父逝世紀念日和國父誕辰紀念日,真是不勝唏噓。
其實中國/臺灣所使用的農民曆是屬於陰陽合曆,計算複雜,幸好在C#中有一個 TaiwanLunisolarCalendar 可用,可惜說明沒寫很清楚,害我踩到坑。
以前學過19年間大約有7個閏月,每年最多就只會有一個閏月,所以也就是19年中大約有7個閏年;我查了一下,似乎現在的算法又不一定,但只要心裡有底知道閏年不少就好。因為我只要反查陽曆的日期,以端午節為例,一般寫法是:
using System.Globalization; int year= DateTime.Now.Year+1; // 明年 //端午節 農曆 5/5 int month = 5; int day = 5; TaiwanLunisolarCalendar tlc = new TaiwanLunisolarCalendar(); int taiwanYear = year - 1911; // 這裡要用中華民國年
DateTime solarDate = tlc.ToDateTime(taiwanYear, 5, 5, 0, 0, 0, 0); Console.WriteLine(solarDate.ToString("yyyy/MM/dd"));
得到2023/05/23,答案錯了,因為2023年(中國民國112年)是農曆閏年 ,所以要寫成:
using System.Globalization; int year= DateTime.Now.Year+1; // 明年 //端午節 農曆 5/5 int month = 5; int day = 5; TaiwanLunisolarCalendar tlc = new TaiwanLunisolarCalendar(); DateTime solarDate;
//判斷是否為閏年 int taiwanYear = year - 1911; // 這裡要用中華民國年
int iMonth = month; bool isLeapYear = tlc.IsLeapYear(taiwanYear); if (isLeapYear) { //找出該年閏月,例如閏4月會得到5 int leapMonth = tlc.GetLeapMonth(taiwanYear); if (month >= leapMonth) { iMonth++; } } solarDate = tlc.ToDateTime(taiwanYear, iMonth, day, 0, 0, 0, 0); Console.WriteLine(solarDate.ToString("yyyy/MM/dd"));
結果為 2023/06/22 ,正確答案
另外除夕與小年夜也有個小技巧,有時候農曆12月會是30日,有時候是29日,所以要先求得大年初一的日期,再用 AddDays(-1) 與 AddDays(-2) 來算比較簡單。
留言