本程式包含兩個核心類別:SDate 提供靜態日期運算工具(月份天數、閏年判斷、指定年月首日星期),DateGrid 繼承 JWindow 實作無邊框視窗日曆,支援月份切換、今日高亮顯示與關閉功能。
accountDays(int year, int month)使用 switch 判斷月份,二月依 isLeap() 決定 28/29 天。
isLeap(int year)public static boolean isLeap(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
fixDay(int year, int month)採用改良版蔡勒公式:
base_month 陣列儲存各月份的月份偏移量(非閏年)。(year + year/4 + year/400 - year/100 - base_year + base_month[month] + 1) % 7。回傳 0~6 分別代表星期日~六。
JWindow 與 ActionListener無標題列、無邊框視窗,適合作為彈出式日曆選擇器。
design())calendar_ym):BorderLayout,左/右箭頭按鈕(<<、>>)切換月份,中央顯示「年/月」標籤。深藍背景、白色前景。calendar_wd):BorderLayout,北部為星期列(GridLayout(1,7)),星期日紅色、星期六綠色;中央為日期格(changeDays() 動態產生 GridLayout(6,7))。calendar_exit):置中「關閉」按鈕。changeDays()SDate.fixDay() 取得該月 1 號星期(first)與總天數(count)。first 之前放空白 JLabel,之後依序填入 1~count。space_length(1 號前空白數)供今日高亮定位使用。Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("GMT+8"));
int nowDayPos = space_length + c.get(Calendar.DAY_OF_YEAR);
// 注意:此處邏輯僅在「目前顯示月份 = 系統當前月份」時正確
if (realYear == viewYear && realMonth == viewMonth) {
((JComponent) calendarDays.getComponent(nowDayPos)).setBorder(
BorderFactory.createLineBorder(Color.BLUE));
}
注意:原始碼使用 DAY_OF_YEAR 計算位置,僅在「檢視月份 = 當前月份」時正確;跨月顯示時需改用 DAY_OF_MONTH 並加上 first 偏移。
actionPerformed)changeDays() 產生的新面板,並 setVisible(true) 刷新。按下「關閉」或視窗關閉事件均呼叫 dispose() 釋放資源。
public static void main(String[] args) {
new DateGrid(); // 直接啟動視窗
}
SDate 可獨立重用;無邊框視窗適合嵌入其他應用。java.time(Java 8+)簡化日期運算;加入 PropertyChangeListener 通知日期選擇;支援鍵盤導航。