DateTimeFormatter
DateTimeFormatter 用于格式化和解析日期时间,是 SimpleDateFormat 的替代品。
最重要的改进:线程安全。
为什么需要 DateTimeFormatter
SimpleDateFormat 的问题:
java
// ❌ SimpleDateFormat 不是线程安全的
public class DateUtils {
private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
public static Date parse(String date) {
return SDF.parse(date); // ❌ 并发调用会出问题
}
}
// ✅ DateTimeFormatter 是线程安全的
public class DateUtils {
private static DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public static LocalDate parse(String date) {
return LocalDate.parse(date, FMT); // ✅ 安全
}
}常用模式
日期格式
java
import java.time.*;
import java.time.format.*;
LocalDate date = LocalDate.of(2024, 3, 15);
DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(date.format(fmt1)); // "2024-03-15"
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(date.format(fmt2)); // "2024/03/15"
DateTimeFormatter fmt3 = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
System.out.println(date.format(fmt3)); // "2024年03月15日"
DateTimeFormatter fmt4 = DateTimeFormatter.ofPattern("yyyyMMdd");
System.out.println(date.format(fmt4)); // "20240315"时间格式
java
LocalTime time = LocalTime.of(14, 30, 45);
DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(fmt1)); // "14:30:45"
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("HH:mm");
System.out.println(time.format(fmt2)); // "14:30"
DateTimeFormatter fmt3 = DateTimeFormatter.ofPattern("a HH:mm");
System.out.println(time.format(fmt3)); // "下午 14:30"日期时间格式
java
LocalDateTime dt = LocalDateTime.of(2024, 3, 15, 14, 30, 45);
DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(dt.format(fmt1)); // "2024-03-15 14:30:45"
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
System.out.println(dt.format(fmt2)); // "2024-03-15T14:30:45"(ISO 格式)预定义格式器
JDK 内置了很多常用格式:
java
// ISO 标准格式
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dt = LocalDateTime.now();
date.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2024-03-15
time.format(DateTimeFormatter.ISO_LOCAL_TIME); // 14:30:45
dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // 2024-03-15T14:30:45
// 紧凑格式
date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20240315
// 与 Locale 结合
DateTimeFormatter localized = DateTimeFormatter.ofPattern("yyyy年M月d日", Locale.CHINA);
date.format(localized); // "2024年3月15日"解析
java
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// 解析日期
LocalDate date = LocalDate.parse("2024-03-15", fmt);
// 解析时间
LocalTime time = LocalTime.parse("14:30:45", DateTimeFormatter.ofPattern("HH:mm:ss"));
// 解析日期时间
LocalDateTime dt = LocalDateTime.parse("2024-03-15 14:30:45",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));处理解析异常
java
import java.time.format.*;
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try {
LocalDate date = LocalDate.parse("2024-13-45", fmt); // 无效日期
} catch (DateTimeParseException e) {
System.err.println("解析失败: " + e.getMessage());
}
// 或使用 withResolverStyle 宽松解析
DateTimeFormatter lenient = DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withResolverStyle(ResolverStyle.LENIENT);
LocalDate lenientDate = LocalDate.parse("2024-13-45", lenient); // 解析为 2025-02-14带时区的格式化
java
import java.time.zone.*;
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 格式化带时区
DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z");
System.out.println(zdt.format(fmt1)); // "2024-03-15 14:30:45 +08:00"
// 使用预定义格式
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
System.out.println(zdt.format(fmt2)); // "2024-03-15 14:30:45 Asia/Shanghai"常见使用场景
场景一:API 响应格式化
java
@RestController
public class UserController {
private static final DateTimeFormatter FMT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.findById(id);
user.setFormattedDate(user.getCreateTime().format(FMT));
return user;
}
}场景二:文件命名
java
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
String filename = "report_" + now.format(fmt) + ".pdf";
// "report_20240315_143045.pdf"场景三:日志时间格式化
java
public class LogFormatter {
private static final DateTimeFormatter FMT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public String format(Instant timestamp) {
return LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault())
.format(FMT);
}
}模式字母速查
| 字母 | 含义 | 示例 |
|---|---|---|
y | 年 | 2024 |
M | 月 | 03 / March |
d | 日 | 15 |
H | 小时(0-23) | 14 |
h | 小时(1-12) | 2 |
m | 分钟 | 30 |
s | 秒 | 45 |
S | 毫秒 | 123 |
a | AM/PM | 下午 |
E | 星期 | 星期五 / Fri |
Z | 时区偏移 | +08:00 |
VV | 时区 ID | Asia/Shanghai |
小结
| 方法 | 说明 |
|---|---|
DateTimeFormatter.ofPattern() | 创建格式化器 |
localDate.format(formatter) | 格式化为字符串 |
LocalDate.parse(str, formatter) | 从字符串解析 |
DateTimeFormatter.ISO_LOCAL_DATE | 预定义 ISO 格式 |
记住:DateTimeFormatter 是线程安全的,可以在多线程环境中共享使用。
