日期格式化大全:Java SimpleDateFormat vs DateTimeFormatter
日期格式化是开发中的常见需求。本文介绍 Java 中日期格式化的方法和最佳实践。
SimpleDateFormat(旧 API)
基本用法
import java.text.SimpleDateFormat;
import java.util.Date;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(new Date());
// "2024-01-01 12:00:00"
Date parsed = sdf.parse("2024-01-01 12:00:00");
常用格式
| 模式 | 说明 | 示例 |
|---|---|---|
| yyyy | 年 | 2024 |
| MM | 月 | 01 |
| dd | 日 | 01 |
| HH | 时(24小时) | 12 |
| mm | 分 | 00 |
| ss | 秒 | 00 |
| SSS | 毫秒 | 000 |
| E | 星期 | 周一 |
| a | AM/PM | 下午 |
线程安全问题
// ❌ SimpleDateFormat 不是线程安全的
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 多线程并发调用会导致错误
public String formatDate(Date date) {
return sdf.format(date); // 危险!
}
// ✅ 方案1:每次创建新实例
public String formatDate(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
}
// ✅ 方案2:使用 ThreadLocal
private static final ThreadLocal<SimpleDateFormat> sdfLocal =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
// ✅ 方案3:使用 Java 8+ API(推荐)
DateTimeFormatter(新 API)
基本用法
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = LocalDateTime.now().format(formatter);
// "2024-01-01 12:00:00"
LocalDateTime parsed = LocalDateTime.parse("2024-01-01 12:00:00", formatter);
线程安全
// ✅ DateTimeFormatter 是线程安全的
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 可以安全地在多线程中使用
public String formatDateTime(LocalDateTime dateTime) {
return dateTime.format(FORMATTER);
}
预定义格式
// ISO 格式
DateTimeFormatter.ISO_LOCAL_DATE; // 2024-01-01
DateTimeFormatter.ISO_LOCAL_TIME; // 12:00:00
DateTimeFormatter.ISO_LOCAL_DATE_TIME; // 2024-01-01T12:00:00
// 自定义格式
DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
新旧 API 对比
| 特性 | SimpleDateFormat | DateTimeFormatter |
|---|---|---|
| 线程安全 | ❌ | ✅ |
| 不可变 | ❌ | ✅ |
| 性能 | 中 | 高 |
| 推荐度 | ❌ 不推荐 | ✅ 推荐 |
常见格式化场景
1. 中文日期
DateTimeFormatter.ofPattern("yyyy年MM月dd日");
// "2024年01月01日"
DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA);
// "2024年01月01日 星期一"
2. 时间戳转日期
Instant instant = Instant.ofEpochSecond(1704067200);
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.of("Asia/Shanghai"));
String formatted = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
3. 日期计算
LocalDateTime now = LocalDateTime.now();
// 加 7 天
LocalDateTime nextWeek = now.plusDays(7);
// 减 1 小时
LocalDateTime oneHourAgo = now.minusHours(1);
// 获取本月第一天
LocalDateTime firstDay = now.withDayOfMonth(1);
JavaScript 日期格式化
原生 API
const now = new Date();
// toLocaleString
now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
// "2024/01/01 12:00:00"
使用 Day.js(推荐)
import dayjs from 'dayjs';
dayjs().format('YYYY-MM-DD HH:mm:ss');
// "2024-01-01 12:00:00"
dayjs().format('YYYY年MM月DD日');
// "2024年01月01日"
最佳实践
- 使用 Java 8+ API:DateTimeFormatter 线程安全
- 预定义格式:常用格式定义为常量
- 使用 Locale:处理国际化日期
- 存储 UTC:数据库存储 UTC 时间
- 显示本地化:前端根据用户地区显示
总结
Java 8 引入的 DateTimeFormatter 完全取代了 SimpleDateFormat。新 API 线程安全、不可变、性能更好,推荐所有新项目使用。