前端/JSON 傳遞日期字符串(如 "2012-08-25"),後端需解析為 Date 對象,或轉換為其他格式字符串(如 "2012年8月25日")用於展示/存儲。
String input = "2012-08-25";
// 1. 解析器:匹配輸入格式
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd");
// 2. 格式化器:輸出目標格式
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年M月d日");
try {
Date date = parser.parse(input); // String → Date
String output = formatter.format(date); // Date → String
System.out.println(output); // 2012年8月25日
} catch (ParseException e) {
e.printStackTrace();
}
| 模式字母 | 含義 | 示例 |
|---|---|---|
| y | 年 | 2012 / 12 |
| M | 月 | 08 / 8 / Aug |
| d | 日 | 25 / 5 |
| H | 時(24制) | 14 / 2 |
| m | 分 | 05 / 5 |
| s | 秒 | 09 / 9 |
| S | 毫秒 | 123 |
| E | 星期 | 週六 |
| a | AM/PM | PM |
| Z | 時區偏移 | +0800 |
String str = "2012/08/25";
SimpleDateFormat p = new SimpleDateFormat("yyyy/MM/dd");
SimpleDateFormat f = new SimpleDateFormat("yyyy年MM月dd日");
System.out.println(f.format(p.parse(str))); // 2012年08月25日
String dt = "2023-10-01 14:30:45";
SimpleDateFormat p = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd HH:mm");
System.out.println(f.format(p.parse(dt))); // 2023/10/01 14:30
SimpleDateFormat 非線程安全,多線程共用實例會導致解析錯誤或數據競爭。
private static final ThreadLocal<SimpleDateFormat> TL_PARSER =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static Date parse(String s) throws ParseException {
return TL_PARSER.get().parse(s);
}
public static Date parse(String s) throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd").parse(s); // 無共享,安全
}
// 解析
LocalDate date = LocalDate.parse("2012-08-25", DateTimeFormatter.ISO_LOCAL_DATE);
// 格式化
String out = date.format(DateTimeFormatter.ofPattern("yyyy年M月d日"));
// 與 Date 互轉
Date d = Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
LocalDate ld = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
DateTimeFormatter 不可變且線程安全,可靜態常量複用;LocalDate/LocalDateTime/Instant 語義明確。SimpleDateFormat;ThreadLocal 或局部新建保證線程安全;ParseException 並轉換為業務異常,提供友好提示。