在 Java 8 引入全新 java.time 套件之前,java.util.Date、Calendar 與 SimpleDateFormat 是日期時間處理的主力軍。儘管舊 API 存在線程不安全、月份從 0 開始等坑點,但在大量存量專案中仍廣泛使用。本文系統整理核心用法,助你快速避坑。
Calendar cal = Calendar.getInstance();
cal.clear(); // 必須先清空,避免繼承系統當前時間殘留值
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1); // 月份 0-based
int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
// Calendar -> Date
Date date = cal.getTime();
// Date -> Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 注意 HH 為 24 小時制
String formatted = sdf.format(new Date());
// 某日為當年第幾週
cal.set(2006, 8, 3); // 2006-09-03
int weekOfYear = cal.get(Calendar.WEEK_OF_YEAR);
// 某年第 N 週的周一日期
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(sdf.format(cal.getTime())); // 2006-01-02
add() 會推算大月份/年份;roll() 僅在當前欄位循環(如 9 月 3 日 roll -4 天 → 8 月 29 日,而非 8 月 30 日)。
單純用毫秒差除以 86400000 會因時間分量導致誤差(如 20:00 到隔天 08:00 算 0 天)。改進做法:
public int getDaysBetween(Calendar d1, Calendar d2) {
if (d1.after(d2)) { Calendar tmp = d1; d1 = d2; d2 = tmp; }
int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
int y2 = d2.get(Calendar.YEAR);
if (d1.get(Calendar.YEAR) != y2) {
d1 = (Calendar) d1.clone();
do {
days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);
d1.add(Calendar.YEAR, 1);
} while (d1.get(Calendar.YEAR) != y2);
}
return days;
}
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())sdf.parse("2003-05-13")new SimpleDateFormat("E").format(date)DATE(無時間)→ java.sql.DateDATETIME → java.sql.Timestamp提示:新專案強烈建議遷移至 Java 8+java.time(LocalDateTime、ZonedDateTime、DateTimeFormatter),享受不可變、線程安全、API 清晰的現代體驗。