問卷發布後 30 天自動失效,需計算結束時間。
import java.util.Calendar;
import java.util.Date;
public class DateCalcWithCalendar {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(); // 當前時間
Date start = cal.getTime(); // 發布時間
System.out.println("開始: " + start);
// 核心:直接操作 DAY_OF_YEAR 自動跨月跨年
int dayOfYear = cal.get(Calendar.DAY_OF_YEAR);
cal.set(Calendar.DAY_OF_YEAR, dayOfYear + 30);
Date end = cal.getTime(); // 30 天后
System.out.println("結束: " + end);
// 其他常用操作
cal.add(Calendar.MONTH, 3); // 加 3 月
cal.add(Calendar.YEAR, -1); // 減 1 年
cal.add(Calendar.HOUR, 12); // 加 12 小時
}
}
| 常量 | 含義 |
|---|---|
| ERA | 紀元 (BC/AD) |
| YEAR | 年 |
| MONTH | 月 (0=1月, 11=12月) |
| WEEK_OF_YEAR | 年中第幾週 |
| DAY_OF_MONTH / DATE | 月內第幾天 |
| DAY_OF_YEAR | 年內第幾天 |
| DAY_OF_WEEK | 週幾 (1=星期日) |
| HOUR / HOUR_OF_DAY | 12/24 小時制 |
| MINUTE / SECOND / MILLISECOND | 分/秒/毫秒 |
cal.set(Calendar.MONTH, 11) 才是 12 月。cal.add() 修改原對象,非線程安全。getInstance() 使用默認時區,跨時區部署易出錯。ThreadLocal 復用或遷移新 API。import java.time.*;
import java.time.format.DateTimeFormatter;
public class DateCalcWithJavaTime {
public static void main(String[] args) {
// 不可變、線程安全、清晰語義
LocalDateTime now = LocalDateTime.now(); // 當前日期時間
LocalDateTime start = now; // 發布時間
LocalDateTime end = start.plusDays(30); // +30 天
System.out.println("開始: " + start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
System.out.println("結束: " + end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// 豐富運算
end = start.plusMonths(3).minusYears(1).plusHours(12);
// 精確到納秒、支援時區
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 期間計算
Period p = Period.between(start.toLocalDate(), end.toLocalDate());
Duration d = Duration.between(start, end);
}
}
| 維度 | Calendar | java.time (LocalDateTime 等) |
|---|---|---|
| 線程安全 | 否 (可變) | 是 (不可變) |
| API 設計 | get/set/add 混雜 | plus/minus/with 流暢 |
| 時區處理 | 隱式、易錯 | 顯式 ZoneId/ZoneOffset |
| 日期時間分離 | 無 (Date 混雜) | LocalDate / LocalTime / LocalDateTime |
| 格式化 | SimpleDateFormat (非線程安全) | DateTimeFormatter (線程安全) |
| 空值處理 | null 滿天飛 | Optional / 明確非空 |
// Calendar → LocalDateTime
LocalDateTime ldt = calendar.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
// LocalDateTime → Calendar
Calendar cal = Calendar.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
setObject/getObject 操作 LocalDateTime、LocalDate、Instant。Calendar 曾是 Java 日期運算的主力,但其可變性、0 基月、時區隱式等設計缺陷在高併發、分布式系統中頻發事故。**Java 8 java.time 包 (JSR-310) 以不可變、領域驅動設計徹底解決這些問題**,是現代 Java 日期時間處理的唯一標準選擇。理解 Calendar 的歷史包袱,更能體會新 API 的優雅。