核心類體系總覽
| 類別 | 套件 | 特點 | 適用場景 |
| Date | java.util | 可變、含時分秒、精度至毫秒 | 簡單時間戳、傳統 API 互操作 |
| Calendar | java.util | 抽象類、支援欄位運算、時區感知 | 複雜日期運算(加減天/月、週期計算) |
| Date | java.sql | 僅含日期(無時間),JDBC 專用 | 資料庫 DATE 欄位映射 |
| Time | java.sql | 僅含時間(無日期),JDBC 專用 | 資料庫 TIME 欄位映射 |
| Timestamp | java.sql | 含日期時間+奈秒,JDBC 專用 | 資料庫 TIMESTAMP 欄位映射(推薦) |
| DateFormat/SimpleDateFormat | java.text | 格式化/解析、非執行緒安全 | 字串↔日期轉換、自訂格式輸出 |
關鍵避坑指南
1. java.sql.Date/Time 缺失元件會拋異常
java.sql.Date d = new java.sql.Date(System.currentTimeMillis());
d.getHours(); // 拋 IllegalArgumentException
建議:資料庫層統一使用 java.sql.Timestamp 或 LocalDateTime(JPA 2.2+)。
2. SimpleDateFormat 非執行緒安全
// 錯誤:共享實例導致亂碼/異常
static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
// 正確:ThreadLocal 或每次 new / DateTimeFormatter (Java 8+)
ThreadLocal<SimpleDateFormat> tl = ThreadLocal.withInitial(() ->
new SimpleDateFormat("yyyy-MM-dd"));
Java 8+ 新日期時間 API (java.time) —— 現代開發首選
不可變、執行緒安全、領域模型清晰(Instant/LocalDate/ZonedDateTime/Duration/Period)。
常用類對照表
| 舊類別 | 新類別 | 說明 |
| Date | Instant / LocalDateTime | 時間戳 / 本地日期時間 |
| Calendar | ZonedDateTime | 帶時區日期時間 |
| Date (SQL) | LocalDate | 純日期 |
| Time (SQL) | LocalTime | 純時間 |
| Timestamp | LocalDateTime / OffsetDateTime | 日期時間/帶偏移量 |
| SimpleDateFormat | DateTimeFormatter | 格式化/解析、執行緒安全 |
核心操作範例
// 當前時間
LocalDateTime now = LocalDateTime.now();
Instant instant = Instant.now();
// 格式化
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = now.format(fmt);
// 解析
LocalDateTime parsed = LocalDateTime.parse("2025-01-15 14:30:00", fmt);
// 日期運算
LocalDate tomorrow = LocalDate.now().plusDays(1);
LocalDate nextMonth = LocalDate.now().plus(1, ChronoUnit.MONTHS);
Period period = Period.between(LocalDate.of(2020,1,1), LocalDate.now());
// 時區轉換
ZonedDateTime taipei = ZonedDateTime.now(ZoneId.of("Asia/Taipei"));
ZonedDateTime utc = taipei.withZoneSameInstant(ZoneOffset.UTC);
// 舊 API 互轉
Date legacy = Date.from(instant);
Instant back = legacy.toInstant();
SimpleDateFormat 格式化符號速查
| 符號 | 含義 | 範例 |
| y | 年 | 2025 / 25 |
| M | 月 | 07 / Jul / July |
| d | 日 | 05 / 5 |
| H | 時 (0-23) | 14 |
| h | 時 (1-12) | 02 |
| m | 分 | 05 |
| s | 秒 | 09 |
| S | 毫秒 | 123 |
| a | AM/PM | PM |
| Z | 時區偏移 | +0800 |
最佳實踐總結
- 新專案全面採用 java.time,僅在維護舊代碼時使用 Date/Calendar。
- 資料庫交互層使用
LocalDateTime / OffsetDateTime,配合 JPA 2.2+ 或 MyBatis TypeHandler 自動映射。
- 格式化統一使用
DateTimeFormatter(不可變、執行緒安全),定義為 static final 常量。
- 序列化傳輸建議採用 ISO-8601 標準格式(
yyyy-MM-dd'T'HH:mm:ssXXX)。
- 避免在業務邏輯中直接操作時區,集中在邊界層(Controller/DTO 轉換)處理。