在 Java 中,处理时间的 API 主要有两套:
- 旧版日期时间 API(java.util.Date / java.util.Calendar)
- 新版日期时间 API(java.time 包,JDK8+ 推荐使用)
📅 旧版时间 API (java.util)
| 类名 | 是否包含时区 | 表示内容 | 常用方法 | 缺点 | 示例 |
|---|---|---|---|---|---|
java.util.Date | ❌ 否 | UTC 时间戳 | getTime(), setTime(long), toString() | 可变、线程不安全、设计混乱 | Date now = new Date(); System.out.println(now); |
java.util.Calendar | ✅ 是 | 日历日期(默认系统时区) | getInstance(), add(), get(), getTime() | 线程不安全、API 复杂 | Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 1); |
SimpleDateFormat | ✅ 是 | 日期格式化/解析 | format(Date), parse(String), setTimeZone() | 非线程安全,需加锁或使用 ThreadLocal | SimpleDateFormat sdf = new SimpleDateFormat(...); sdf.format(new Date()); |
⭐ 新版时间 API (java.time,JDK8+)
| 类名 | 是否包含时区 | 表示内容 | 常用方法 | 推荐用途 |
|---|---|---|---|---|
Instant | ❌ 否 | UTC 时间戳(秒/纳秒) | now(), ofEpochMilli(long), plusSeconds() | 日志记录、唯一 ID、分布式系统时间同步 |
LocalDate | ❌ 否 | 年月日(如 2025-07-07) | now(), of(), plusDays() | 生日、纪念日等不含时间的日期 |
LocalTime | ❌ 否 | 时分秒(如 14:30:00) | now(), of(), plusMinutes() | 营业时间、定时任务 |
LocalDateTime | ❌ 否 | 年月日 + 时分秒(如 2025-07-07T14:30:00) | now(), of(), plusHours() | 本地事件时间(不涉及时区转换) |
ZonedDateTime | ✅ 是 | 完整带时区时间(如 Asia/Shanghai) | now(ZoneId), withZoneSameInstant() | 跨时区系统、航班时刻 |
OffsetDateTime | ✅ 是 | 偏移时间(如 +08:00) | now(), toZonedDateTime() | 简单时区处理 |
ZoneId | - | 时区 ID(如 Asia/Shanghai) | of(), systemDefault() | 时区管理 |
ZoneOffset | - | 时区偏移(如 +08:00) | ofHours(), UTC | 固定偏移处理 |
Duration | ❌ 否 | 精确时间差(纳秒级) | between(), toHours(), plus() | 计算时间间隔(如超时检测) |
Period | ❌ 否 | 日期差(天/月/年) | between(), plusDays() | 计算日期间隔(如会员有效期) |
DateTimeFormatter | ✅ 是 | 日期格式化/解析 | ofPattern(), format(), parse(), withZone() | 日期字符串转换 |
💡 关键对比总结:
-
线程安全:
- 旧版:❌ 全部线程不安全
- 新版:✅ 全部不可变对象(线程安全)
-
设计理念:
- 旧版:过程式操作(
set,add改变原对象) - 新版:函数式操作(
plus,with返回新对象)
- 旧版:过程式操作(
-
时区处理:
- 旧版:隐式依赖系统时区
- 新版:显式指定时区(
ZoneId)
-
API 清晰度:
- 旧版:
Calendar.MONTH从 0 开始等反人类设计 - 新版:人性化枚举(
Month.JANUARY)
- 旧版:
最佳实践:新项目应优先使用
java.timeAPI,遗留系统逐步迁移。处理时区时明确使用ZonedDateTime或OffsetDateTime,避免隐式转换。
推荐组合用法
| 场景 | 推荐 API 组合 |
|---|---|
| 记录时间戳(日志、ID生成) | Instant |
| 显示给用户看的时间 | ZonedDateTime + DateTimeFormatter |
| 日期运算(如“明天”、“下周几”) | LocalDate |
| 跨时区时间转换 | ZonedDateTime + withZoneSameInstant() |
| 时间差计算(精确到毫秒) | Duration |
| 日期差计算(按天、月) | Period |
总结对比表
| API 类名 | 是否带时区 | 精度 | 推荐用途 | 是否线程安全 |
|---|---|---|---|---|
Date | ❌ 否(实际是 UTC) | 毫秒 | 兼容旧代码 | ❌ |
Calendar | ✅ 是 | 毫秒 | 日期计算 | ❌ |
SimpleDateFormat | ✅ 是 | - | 格式化 | ❌ |
Instant | ❌ 否 | 纳秒 | 时间戳 | ✅ |
LocalDate / LocalTime / LocalDateTime | ❌ 否 | 天/小时/分钟 | 本地日期操作 | ✅ |
ZonedDateTime | ✅ 是 | 纳秒 | 带时区时间处理 | ✅ |
OffsetDateTime | ✅ 是 | 纳秒 | 固定偏移时间 | ✅ |
Duration | ❌ 否 | 纳秒 | 时间长度计算 | ✅ |
Period | ❌ 否 | 天/月/年 | 日期长度计算 | ✅ |
DateTimeFormatter | ✅ 是 | - | 格式化/解析 | ✅ |