| 類別 | 包 | 特點 | 用途 |
|---|---|---|---|
Date | java.util | 毫秒時間戳封裝,大多方法已棄用 | 時間點傳遞、資料庫交互、序列化 |
Calendar | java.util | 抽象基類,GregorianCalendar 實現 | 日期運算、欄位獲取/設置、國際化 |
DateFormat | java.text | 抽象格式化基類 | 日期↔字串轉換 |
SimpleDateFormat | java.text | 具體實現,**非線程安全** | 自定義模式格式化/解析 |
// 當前時間
Date now = new Date(); // 相當於 new Date(System.currentTimeMillis())
long timestamp = now.getTime(); // 毫秒時間戳
Date specific = new Date(timestamp); // 時間戳還原
// 日期運算 (毫秒級)
long oneDay = 24 * 60 * 60 * 1000L;
Date tomorrow = new Date(now.getTime() + oneDay);
Date yesterday = new Date(now.getTime() - oneDay);
// 兩日期差天數
long diffDays = (date1.getTime() - date2.getTime()) / oneDay;
Calendar cal = Calendar.getInstance(); // 當前時間,默認 Locale/TimeZone
cal.set(2023, Calendar.NOVEMBER, 15); // 月份 0-based: JANUARY=0
cal.add(Calendar.DAY_OF_MONTH, 10); // 加 10 天
cal.add(Calendar.HOUR_OF_DAY, -3); // 減 3 小時
cal.set(Calendar.MINUTE, 30); // 設定分鐘
Date result = cal.getTime(); // 轉回 Date
// 獲取欄位
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // 轉為 1-based
int day = cal.get(Calendar.DAY_OF_MONTH);
int weekDay = cal.get(Calendar.DAY_OF_WEEK); // SUNDAY=1
// 常用模式字母
// y=年 M=月 d=日 H=時(24) m=分 s=秒 S=毫秒 E=星期 a=AM/PM z=時區
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
// 格式化 Date → String
String formatted = sdf.format(new Date()); // "2023-11-15 14:30:05"
// 解析 String → Date
Date parsed = sdf.parse("2023-11-15 14:30:05"); // 拋 ParseException
// 解析特定模式 (如只有年月周)
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM w E");
Date d = sdf2.parse("2023-11 3 星期三");
SimpleDateFormat 非線程安全!** 多線程共用實例會導致解析錯誤、數據競爭甚至死循環。
public class DateUtils {
private static final ThreadLocal SDF_YYYYMMDD =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static String format(Date date) {
return SDF_YYYYMMDD.get().format(date);
}
public static Date parse(String str) throws ParseException {
return SDF_YYYYMMDD.get().parse(str);
}
}
// 每次使用 new 實例,無共享風險
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
// 線程安全、不可變、API 清晰
LocalDate date = LocalDate.now();
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = ldt.format(fmt);
LocalDate parsed = LocalDate.parse("2023-11-15", fmt);
// 期間運算
LocalDate nextWeek = date.plusWeeks(1);
Period p = Period.between(date, nextWeek); // P1W
// 1. 獲取本月第一天/最後一天
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1); // 第一天
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); // 最後一天
// 2. 判斷閏年
boolean leap = cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
// 3. 日期區間迭代
for (Date d = start; !d.after(end); d = addDays(d, 1)) { ... }
// 4. 時間戳轉換 (Java 8)
Instant instant = Instant.now();
long ms = instant.toEpochMilli();
Instant instant2 = Instant.ofEpochMilli(ms);
| 舊類 | 新類 (java.time) | 優勢 |
|---|---|---|
| Date | Instant / LocalDateTime | 不可變、納秒精度、清晰語義 |
| Calendar | ZonedDateTime / LocalDate | 線程安全、流式 API、時區分離 |
| SimpleDateFormat | DateTimeFormatter | 線程安全、預編譯、支援解析嚴格模式 |
| TimeZone | ZoneId / ZoneOffset | IANA 時區數據庫、歷史規則支援 |
Java 8+ 專案**強制禁用** `SimpleDateFormat` 共享實例,新代碼優先使用 `java.time`;舊代碼逐步重構或用 `ThreadLocal` 過渡。