為什麼要新 API?
| 舊 API 痛點 | 新 API 解決 |
Date 月份 0-11(1月=0) | Month 枚舉,JANUARY=1 |
Date/SimpleDateFormat 非線程安全 | LocalDate 等不可變類,天然線程安全 |
Date 混雜日期、時間、毫秒 | 分離 LocalDate(日期) LocalTime(時間) LocalDateTime(日期時間) |
| 計算「下月第一天」需 Calendar 大量代碼 | TemporalAdjusters 一行搞定 |
核心類速覽
| 類 | 用途 | 示例 |
LocalDate | 只有日期 | 2024-07-05 |
LocalTime | 只有時間 | 14:30:45.123 |
LocalDateTime | 日期+時間 | 2024-07-05T14:30:45.123 |
ZonedDateTime | 帶時區 | 2024-07-05T14:30:45+08:00[Asia/Shanghai] |
Instant | 時間戳(納秒精度) | 2024-07-05T06:30:45.123Z |
Duration | 時間間隔 | PT2H30M |
Period | 日期間隔 | P1Y2M3D |
LocalDate 實戰
創建
LocalDate today = LocalDate.now(); // 當前日期
LocalDate christmas = LocalDate.of(2024, 12, 25); // 指定日期
LocalDate parsed = LocalDate.parse("2024-02-28"); // ISO 格式解析
// LocalDate.parse("2024-02-29"); // 拋 DateTimeParseException:無效日期
強大的調整器
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth()); // 本月1號
LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth()); // 本月最後一天
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); // 下個周一
LocalDate firstMon2025 = LocalDate.of(2025,1,1).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
加減運算
LocalTime now = LocalTime.now(); // 含納秒
LocalTime noNano = now.withNano(0); // 去除納秒
LocalTime noon = LocalTime.of(12, 0, 0); // 12:00:00
LocalTime parsed = LocalTime.parse("12:00:00.123"); // 支持 3 種 ISO 格式
LocalDateTime 綜合
LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2024, 7, 5, 14, 30, 45);
LocalDateTime parsed = LocalDateTime.parse("2024-07-05T14:30:45");
格式化與解析:DateTimeFormatter
// 線程安全、不可變
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String str = LocalDateTime.now().format(fmt); // 2024年07月05日 14:30:45
LocalDateTime parsed = LocalDateTime.parse("2024年07月05日 14:30:45", fmt);
JDBC 交互:無縫映射
| SQL 類型 | Java 8 類型 |
| DATE | LocalDate |
| TIME | LocalTime |
| TIMESTAMP | LocalDateTime |
// PreparedStatement
ps.setObject(1, LocalDate.now()); // 寫入 DATE
ps.setObject(2, LocalTime.now()); // 寫入 TIME
ps.setObject(3, LocalDateTime.now()); // 寫入 TIMESTAMP
// ResultSet
LocalDate date = rs.getObject(1, LocalDate.class);
LocalTime time = rs.getObject(2, LocalTime.class);
LocalDateTime dt = rs.getObject(3, LocalDateTime.class);
與舊 API 互操作
// Date → LocalDateTime
Date date = new Date();
LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
// LocalDateTime → Date
Date converted = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
最佳實踐清單
- 新代碼全面使用 java.time,禁用
Date/Calendar/SimpleDateFormat。
- 傾向使用
LocalDate/LocalTime 而非 LocalDateTime,語義更精確。
- 格式化統一用
DateTimeFormatter(不可變、線程安全),可定義為 static final 常量。
- 時區敏感業務(定時任務、跨地域)必須用
ZonedDateTime + ZoneId。
- 數據庫交換優先用
LocalDateTime(無時區),存儲時由驅動按連接時區轉換。
總結
Java 8 日期時間 API 通過不可變類、清晰分離日期時間、豐富調整器、線程安全格式化,徹底解決了舊 API 的設計缺陷。掌握 LocalDate、LocalTime、LocalDateTime、DateTimeFormatter、TemporalAdjusters 核心組件,即可輕鬆應對 99% 的日期時間業務場景。