java.util.Date 核心認知
- 表示特定瞬間,精確到毫秒(UTC 1970-01-01 00:00:00 起的毫秒數)。
- 不包含時區信息,打印時默認用 JVM 當前時區格式化。
- 大多數構造/獲取方法已棄用(如
getYear()),建議遷移至 java.time (Java 8+)。
兩個構造方法
| 構造方法 | 說明 | 示例 |
Date() | 當前時間 | new Date() |
Date(long millis) | 指定毫秒數 | new Date(151516L) |
基本用法
public class DateBasic {
public static void main(String[] args) {
Date now = new Date();
System.out.println("直接打印: " + now); // toString() 默認格式
System.out.println("toString(): " + now.toString());
Date past = new Date(151516L);
System.out.println("指定毫秒: " + past);
}
}
SimpleDateFormat:格式化與解析
常用模式字母
| 字母 | 含義 | 示例 |
| y | 年 | 2024 / 24 |
| M | 月 | 07 / Jul / July |
| d | 日 | 05 |
| H | 時 (0-23) | 14 |
| h | 時 (1-12) | 02 |
| m | 分 | 05 |
| s | 秒 | 09 |
| S | 毫秒 | 123 |
| a | AM/PM | PM |
| z | 時區 | CST / GMT+08:00 |
格式化:Date → String
public class FormatDemo {
public static void main(String[] args) {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss a z");
String formatted = sdf.format(now);
System.out.println("格式化結果: " + formatted);
// 輸出示例: 2024.07.05 at 14:30:45 PM CST
}
}
解析:String → Date
public class ParseDemo {
public static void main(String[] args) throws ParseException {
String str = "2024-07-05 14:30:45";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(str);
System.out.println("解析結果: " + date);
}
}
⚠️ 線程安全陷阱與最佳實踐
問題
SimpleDateFormat 非線程安全,多線程共享實例會導致解析錯誤、數據錯亂甚至崩潰。
解決方案對比
| 方案 | 代碼 | 優點 | 缺點 |
| 局部變量 | 方法內 new | 簡單、絕對安全 | 頻繁創建對象 |
| ThreadLocal | 每線程一實例 | 復用、高性能 | 代碼較繁瑣 |
| FastDateFormat (Apache Commons Lang) | FastDateFormat.getInstance(pattern) | 線程安全、單例 | 需第三方依賴 |
| Java 8+ DateTimeFormatter | DateTimeFormatter.ofPattern(pattern) | 不可變、線程安全、功能強 | 需 Java 8+ |
ThreadLocal 封裝範例
public class SafeDateFormat {
private static final ThreadLocal<SimpleDateFormat> TL_SDF = ThreadLocal.withInitial(
() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
);
public static String format(Date date) {
return TL_SDF.get().format(date);
}
public static Date parse(String str) throws ParseException {
return TL_SDF.get().parse(str);
}
}
Java 8+ 現代替代:java.time 包
強烈建議新項目直接使用:
LocalDate、LocalTime、LocalDateTime:無時區日期時間。
ZonedDateTime、Instant:帶時區/時間戳。
DateTimeFormatter:不可變、線程安全、功能豐富。
// Java 8 現代寫法
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy.MM.dd 'at' HH:mm:ss");
System.out.println(now.format(fmt));
// 互操作
Date oldDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
LocalDateTime converted = LocalDateTime.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
總結
Date 只是時間戳容器,格式化/解析靠 SimpleDateFormat。
- 切勿共享 SimpleDateFormat 實例,用 ThreadLocal 或遷移 Java 8
DateTimeFormatter。
- 舊系統維護用
Date,新項目全面拥抱 java.time。