首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 萬年曆實現全解析:從基礎算法到 GUI 完整項目

     編輯:Java 相關知識

前言

萬年曆是 Java 初學者練習日期計算、控制流、GUI 開發的經典項目。本文將由淺入深,展示三種不同複雜度的實現方案:

  1. 控制台版:手寫核心算法(基姆拉爾森公式),理解閏年、星期、天數計算邏輯。
  2. 工具類版:封裝可復用的 CalendarUtil,支援「某年第幾天/第幾周/星期幾」等查詢。
  3. Swing GUI 版:集成下拉選單選擇年月、實時時鐘、多線程刷新,體驗完整桌面應用開發流程。

方案一:控制台交互版(掌握核心算法)

核心邏輯說明

  • 以 1900-01-01(星期一) 為基準點,累加總天數。
  • 閏年判斷:(year%4==0 && year%100!=0) || year%400==0。
  • 根據總天數 % 7 推導目標月 1 號是星期幾,再按列打印日曆表。

關鍵代碼片段

public class ConsoleCalendar {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("請輸入年份:");
        int year = sc.nextInt();
        System.out.print("請輸入月份:");
        int month = sc.nextInt();

        int totalDays = 0;
        // 1. 累加 1900 年至 year-1 的天數
        for (int y = 1900; y < year; y++) {
            totalDays += isLeap(y) ? 366 : 365;
        }
        // 2. 累加 year 年 1 月至 month-1 月的天數
        for (int m = 1; m < month; m++) {
            totalDays += daysInMonth(year, m);
        }
        // 3. 1 號星期幾(0=周日...6=周六,這裡以周一為起始調整)
        int weekDay = (totalDays + 1) % 7; // 1900-01-01 是周一

        // 4. 打印表頭與空格佔位
        System.out.println("日\t一\t二\t三\t四\t五\t六");
        for (int i = 0; i < weekDay; i++) System.out.print("\t");

        // 5. 打印日期並換行
        int days = daysInMonth(year, month);
        for (int d = 1; d <= days; d++) {
            System.out.print(d + "\t");
            if ((weekDay + d) % 7 == 0) System.out.println();
        }
    }

    static boolean isLeap(int y) {
        return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
    }
    static int daysInMonth(int y, int m) {
        if (m == 2) return isLeap(y) ? 29 : 28;
        if (m == 4 || m == 6 || m == 9 || m == 11) return 30;
        return 31;
    }
}

方案二:工具類版(基姆拉爾森公式 + 豐富查詢)

封裝 CalendarUtil,提供以下靜態方法:

  • cptDay(year, month, day):該日期是當年的第幾天。
  • getWeek(year, month, day):基姆拉爾森公式計算星期(0=周一...6=周日)。
  • weekCount(year, month, day):該日期屬於當年的第幾周。
  • printCal(year):打印全年日曆。

基姆拉爾森公式核心實現

// 注意:1、2 月視作上一年的 13、14 月
public static int getWeek(int year, int month, int day) {
    if (month < 3) { month += 12; year--; }
    return (day + 2*month + 3*(month+1)/5 + year + year/4 - year/100 + year/400) % 7;
}

方案三:Swing GUI 版(生產級桌面應用)

功能特性

  • 頂部:年份/月份下拉框 + 「查詢」按鈕。
  • 中部:7×6 網格顯示日曆,周末紅色高亮,今日背景標記。
  • 底部:實時數字時鐘(HH:mm:ss),獨立線程每秒刷新。
  • 響應式布局,居中顯示,禁止調整大小。

核心類結構

public class CalendarApp {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true));
    }
}

class MainFrame extends JFrame {
    private JComboBox yearBox, monthBox;
    private JLabel[] dayLabels = new JLabel[49];
    private Calendar today = Calendar.getInstance();

    MainFrame() {
        initUI();
        initData();
        startClock();
    }
    // ... 初始化下拉框 1-9999 年、1-12 月
    // ... 根據 yearBox/monthBox 選擇重繪日曆
    // ... 內部類 Clock extends Canvas implements Runnable 繪製時鐘
}

方案四:利用 JDK Calendar API 簡化邏輯(生產環境推薦)

實際項目中,建議直接使用 java.util.Calendar 或 Java 8+ 的 java.time 包,避免手寫算法出錯:

public class JdkCalendarDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("輸入年份:");
        int year = sc.nextInt();

        Calendar cal = Calendar.getInstance();
        for (int m = 0; m < 12; m++) {
            cal.set(year, m, 1);
            printMonth(cal);
        }
    }
    static void printMonth(Calendar c) {
        c.set(Calendar.DAY_OF_MONTH, 1);
        System.out.printf("\n========= %d 月 =========\n", c.get(Calendar.MONTH)+1);
        String[] ws = {"日","一","二","三","四","五","六"};
        for (String w : ws) System.out.print(w + "\t");
        System.out.println();

        int offset = c.get(Calendar.DAY_OF_WEEK) - 1; // 周日=1
        for (int i = 0; i < offset; i++) System.out.print("\t");

        int month = c.get(Calendar.MONTH);
        while (c.get(Calendar.MONTH) == month) {
            System.out.print(c.get(Calendar.DAY_OF_MONTH) + "\t");
            if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) System.out.println();
            c.add(Calendar.DAY_OF_MONTH, 1);
        }
    }
}

總結與避坑指南

方案適用場景優點缺點
手寫算法教學、面試、嵌入式無標準庫環境深度理解日期本質易出錯、維護成本高
工具類封裝項目內部通用日期查詢API 統一、可測試仍需自行維護算法正確性
Swing GUI桌面工具、教學演示直觀、功能全Swing 技術棧較老舊
JDK Calendar / java.time所有生產環境標準、線程安全、時區支持完善需學習新 API

建議:學習階段請手寫算法理解原理;實際開發務必使用 java.time.LocalDate、YearMonth、DateTimeFormatter 等現代 API,配合 TemporalAdjusters 可一行代碼搞定「本月第一天/最後一天/下個工作日」等複雜需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved