java.util.Calendar 是 JDK 1.1 引入的抽象類,用於日期時間運算,功能比 Date 強大,支持國際化、時區、字段操作。實際使用時獲取具體實現類(如 GregorianCalendar)實例。
// 1. 當前時間(默認時區、默認 Locale)
Calendar cal = Calendar.getInstance();
// 2. 指定時區/ Locale
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"), Locale.CHINA);
// 3. 從 Date 轉換
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
// 4. 從毫秒數創建
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
Calendar cal = Calendar.getInstance();
// 注意:月份從 0 開始 (0=1月, 11=12月)
cal.set(2024, 2, 15); // 2024年3月15日
cal.set(Calendar.YEAR, 2024);
cal.set(Calendar.MONTH, 2); // 3月
cal.set(Calendar.DATE, 15); // 15號
cal.set(Calendar.HOUR_OF_DAY, 14); // 24制 14:00
cal.set(Calendar.MINUTE, 30);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
| 常量 | 含義 | 取值範圍 |
|---|---|---|
| YEAR | 年份 | 如 2024 |
| MONTH | 月份 | 0-11 (注意!) |
| DATE / DAY_OF_MONTH | 月份中的第幾天 | 1-31 |
| DAY_OF_WEEK | 星期幾 | 1=周日, 2=周一...7=周六 |
| DAY_OF_YEAR | 年份中的第幾天 | 1-366 |
| WEEK_OF_MONTH | 月份中的第幾周 | 1-6 |
| WEEK_OF_YEAR | 年份中的第幾周 | 1-53 |
| HOUR | 12制小時 | 0-11 |
| HOUR_OF_DAY | 24制小時 | 0-23 |
| MINUTE | 分鐘 | 0-59 |
| SECOND | 秒 | 0-59 |
| MILLISECOND | 毫秒 | 0-999 |
| AM_PM | 上午/下午 | 0=AM, 1=PM |
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // +1 轉為人類可讀月份
int day = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1=周日
System.out.printf("%d-%02d-%02d %02d:%02d:%02d 星期%d%n",
year, month, day, hour, minute, second, dayOfWeek);
Calendar cal = Calendar.getInstance(); // 2024-01-31
// 向後推 1 個月 → 2024-02-29 (閏年自動處理)
cal.add(Calendar.MONTH, 1);
// 向前推 100 天
cal.add(Calendar.DATE, -100);
// 加 2 年
cal.add(Calendar.YEAR, 2);
特點:會自動調整其他字段(如月份天數、進位借位),符合日曆邏輯。
Calendar cal = Calendar.getInstance();
cal.set(2024, 0, 31); // 1月31日
// 月份 +1,但不調整日期 → 2月31日 → 自動變為 2月29日(閏年) 或 2月28日
cal.add(Calendar.MONTH, 1); // 正確:2月29日
// roll 不進位
cal.roll(Calendar.MONTH, 1); // 錯誤邏輯:嘗試設置 2月31日 → 內部處理可能異常
區別:add 是真實日期加減,roll 只改指定字段,不聯動其他字段(較少用)。
Calendar c1 = Calendar.getInstance();
c1.set(2024, 0, 1); // 2024-01-01
Calendar c2 = Calendar.getInstance();
c2.set(2024, 11, 31); // 2024-12-31
// c2 在 c1 之後
boolean after = c2.after(c1); // true
boolean before = c2.before(c1); // false
// compareTo (Calendar 實現了 Comparable)
int cmp = c2.compareTo(c1); // 1 (c2 > c1)
// Calendar → Date
Date date = cal.getTime();
// Date → Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// Calendar ↔ 毫秒數
long millis = cal.getTimeInMillis();
cal.setTimeInMillis(millis);
public class CalendarUtils {
/** 獲取當月第一天 00:00:00 */
public static Calendar getMonthStart() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
/** 獲取當月最後一天 23:59:59.999 */
public static Calendar getMonthEnd() {
Calendar cal = getMonthStart();
cal.add(Calendar.MONTH, 1);
cal.add(Calendar.MILLISECOND, -1);
return cal;
}
/** 判斷是否為今天 */
public static boolean isToday(Calendar cal) {
Calendar today = Calendar.getInstance();
return cal.get(Calendar.YEAR) == today.get(Calendar.YEAR)
&& cal.get(Calendar.DAY_OF_YEAR) == today.get(Calendar.DAY_OF_YEAR);
}
/** 格式化輸出 */
public static String format(Calendar cal, String pattern) {
return new SimpleDateFormat(pattern).format(cal.getTime());
}
}
| 坑點 | 說明 | 正確做法 |
|---|---|---|
| 月份 0-11 | MONTH=0 代表 1月 | 設置/讀取時 ±1 |
| 星期 1=周日 | DAY_OF_WEEK: 1=周日 | 轉換邏輯:(day+5)%7+1 → 1=周一 |
| 可變性 | Calendar 可變,set/add 修改原對象 | 需副本時用 clone() 或新建實例 |
| 線程不安全 | SimpleDateFormat 非線程安全 | 用 ThreadLocal 或 DateTimeFormatter (Java 8+) |
| lenient 模式 | 默認寬容模式 (月份13→次年1月) | 嚴格模式:cal.setLenient(false) |
新項目優先使用 java.time (JSR-310):
LocalDate、LocalTime、LocalDateTime - 不可變、線程安全ZonedDateTime - 帶時區DateTimeFormatter - 線程安全格式化Period、Duration - 日期/時間間隔
// Java 8 等價代碼
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextMonth = now.plusMonths(1);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = nextMonth.format(fmt);
Calendar 是 Java 日期時間處理的經典 API,核心掌握:月份 0-11、星期 1=周日、add 做日期運算、getTime/setTime 轉 Date、可變性注意副本。維護舊代碼必會,新項目強烈建議遷移至 java.time 獲得更安全、直觀的體驗。