Java处理时间-java.time
·
在 Java 中,处理日期和时间的类经历了重大演进。根据你使用的 Java 版本不同,推荐使用不同的 API。以下是 全面、清晰、现代 的 Java 时间处理类总结(截至 Java 21):
✅ 推荐:Java 8+ 使用 java.time 包(JSR-310)—— 现代、线程安全、易用
这是目前最推荐的方式,设计优秀,避免了旧 API 的诸多坑。
核心类概览
| 类 | 用途 | 示例 |
|---|---|---|
LocalDateTime |
不带时区的日期+时间(如:2026-02-09T17:30:45) | 业务日志、本地事件 |
LocalDate |
仅日期(如:2026-02-09) | 生日、节假日 |
LocalTime |
仅时间(如:17:30:45) | 营业时间、闹钟 |
ZonedDateTime |
带时区的完整时间(如:2026-02-09T17:30:45+08:00[Asia/Shanghai]) | 全球应用、跨时区调度 |
Instant |
时间戳(UTC,从 1970-01-01T00:00:00Z 开始的纳秒数) | 系统日志、数据库存储 |
Duration |
两个时间点之间的时间量(如:2 小时 30 分) | 计时、间隔 |
Period |
两个日期之间的日期量(如:1 年 2 个月) | 年龄、合同周期 |
DateTimeFormatter |
格式化与解析(替代 SimpleDateFormat) |
"yyyy-MM-dd HH:mm:ss" |
📌 常用示例(Java 8+)
import java.time.*;
import java.time.format.DateTimeFormatter;
public class ModernTimeExample {
public static void main(String[] args) {
// 1. 获取当前时间(系统默认时区)
LocalDateTime now = LocalDateTime.now();
LocalDate today = LocalDate.now();
ZonedDateTime zonedNow = ZonedDateTime.now(); // 带时区
// 2. 创建指定时间
LocalDateTime dt = LocalDateTime.of(2026, 2, 9, 17, 30, 45);
LocalDate date = LocalDate.of(2026, Month.FEBRUARY, 9);
// 3. 格式化输出
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(now.format(formatter)); // 2026-02-09 17:30:45
// 4. 解析字符串
LocalDateTime parsed = LocalDateTime.parse("2026-02-09 17:30:45", formatter);
// 5. 加减操作(不可变,返回新对象)
LocalDateTime tomorrow = now.plusDays(1);
LocalDateTime oneHourAgo = now.minusHours(1);
// 6. 转为时间戳(用于数据库或网络传输)
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
long epochMilli = instant.toEpochMilli(); // 毫秒时间戳
// 7. 从时间戳创建
LocalDateTime fromTs = LocalDateTime.ofInstant(
Instant.ofEpochMilli(epochMilli),
ZoneId.systemDefault()
);
}
}
✅ 优点:不可变、线程安全、API 清晰、无夏令时陷阱(合理处理)
⚠️ 旧版 API(Java 8 之前)—— 不推荐新项目使用
这些类存在设计缺陷(非线程安全、月份从 0 开始、可变等),但你可能在老代码中见到。
| 类 | 问题 | 替代方案 |
|---|---|---|
java.util.Date |
表示时间戳,但命名误导(实际包含时间),可变,非线程安全 | Instant 或 LocalDateTime |
java.util.Calendar |
复杂、月份从 0 开始(Jan=0)、可变、非线程安全 | LocalDateTime / ZonedDateTime |
java.text.SimpleDateFormat |
非线程安全! 格式化性能差 | DateTimeFormatter |
❌ 旧 API 示例(仅作对比)
// 危险!SimpleDateFormat 非线程安全
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2026-02-09 17:30:45"); // 注意:月份不用减1?其实这里字符串解析没问题,但构造 Date 时 Calendar.MONTH 从0开始!
// Calendar 月份从0开始(反人类)
Calendar cal = Calendar.getInstance();
cal.set(2026, Calendar.FEBRUARY, 9); // 正确(因为 Calendar.FEBRUARY = 1)
// cal.set(2026, 1, 9); // 也是2月,但容易混淆
🔁 新旧 API 互转(兼容老系统)
// Date → Instant → LocalDateTime
Date oldDate = new Date();
Instant instant = oldDate.toInstant();
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
// LocalDateTime → Date
LocalDateTime ldt = LocalDateTime.now();
Date newDate = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
📌 最佳实践建议
- 新项目一律使用
java.time(JSR-310) - 永远不要在多线程环境中共享
SimpleDateFormat - 存储时间戳到数据库时,优先用
Instant(UTC)或long毫秒值 - 显示给用户时,再根据其时区格式化(如
ZonedDateTime) - 避免使用
System.currentTimeMillis()做业务逻辑,改用Instant.now()
🧩 补充:第三方库(通常不需要)
- Joda-Time:
java.time的前身,Java 8 后官方已吸收其优点,无需再引入 - ThreeTenBP:Android 或 Java 6/7 项目可使用(Backport of JSR-310)
总结
| 场景 | 推荐类 |
|---|---|
| 本地日期时间(无时区) | LocalDateTime |
| 仅日期 | LocalDate |
| 带时区的时间 | ZonedDateTime |
| 时间戳(系统/数据库) | Instant |
| 格式化/解析 | DateTimeFormatter |
| 时间间隔 | Duration(时分秒)、Period(年月日) |
💡 记住:Java 8 的
java.time是处理时间的终极答案,简洁、安全、强大。
更多推荐




所有评论(0)