在 Java 中,处理时间的 API 主要有两套:
- 旧版日期时间 API(java.util.Date / java.util.Calendar)
- 新版日期时间 API(java.time 包,JDK8+ 推荐使用)
下面我将分别列出这两类 API 的常用类、是否支持时区、常见方法及推荐用途。
✅ 一、旧版时间 API(java.util
)
1. java.util.Date
特性 | 描述 |
---|---|
是否包含时区? | ❌ 否(本质是 UTC 时间戳) |
常用方法 | getTime() 、setTime(long) 、toString() (输出带本地时区) |
缺点 | 可变、线程不安全、设计混乱 |
示例:
java
Date now = new Date();
System.out.println(now); // 输出格式:Sat Apr 05 14:30:00 CST 2025
2. java.util.Calendar
特性 | 描述 |
---|---|
是否包含时区? | ✅ 是(默认系统时区,可设置) |
常用方法 | getInstance()、add()、get()、getTime() |
缺点 | 线程不安全、API 复杂 |
示例:
java
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 1);
System.out.println(cal.getTime());
3. java.text.SimpleDateFormat
特性 | 描述 |
---|---|
是否支持时区? | ✅ 是 |
常用方法 | format(Date)、parse(String) |
缺点 | 非线程安全,需加锁或使用 ThreadLocal |
示例:
java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(sdf.format(new Date()));
✅ 二、新版时间 API(java.time
,推荐使用)
JDK8 引入,位于
java.time
包下,设计更合理、线程安全、支持时区、易读性强。
1. Instant
------ 时间戳(UTC)
特性 | 描述 |
---|---|
是否包含时区? | ❌ 否 |
表示什么? | UTC 时间戳(从 1970-01-01T00:00:00Z 开始的秒/纳秒) |
常用方法 | now() 、ofEpochMilli(long) 、plusSeconds() |
推荐用途 | 日志记录、唯一 ID、分布式系统时间同步 |
示例:
java
Instant now = Instant.now(); // 当前 UTC 时间
Instant later = now.plusSeconds(3600); // 1小时后
2. LocalDate
/ LocalTime
/ LocalDateTime
------ 不带时区的时间
类名 | 是否有时区? | 表示内容 | 常用方法 |
---|---|---|---|
LocalDate |
❌ 否 | 年月日 | now() 、of() 、plusDays() |
LocalTime |
❌ 否 | 时分秒 | now() 、of() 、plusMinutes() |
LocalDateTime |
❌ 否 | 年月日 + 时分秒 | now() 、of() 、plusHours() |
示例:
java
LocalDate today = LocalDate.now();
LocalDateTime now = LocalDateTime.now();
3. ZonedDateTime
/ OffsetDateTime
------ 带时区的时间
类名 | 是否有时区? | 表示内容 | 常用方法 |
---|---|---|---|
ZonedDateTime |
✅ 是 | 完整带时区的时间(如 Asia/Shanghai ) |
now(ZoneId) 、withZoneSameInstant() |
OffsetDateTime |
✅ 是 | 偏移时间(如 +08:00 ) |
now() 、toZonedDateTime() |
示例:
java
ZoneId zone = ZoneId.of("Europe/London");
ZonedDateTime londonTime = ZonedDateTime.now(zone);
// 转换为另一个时区
ZonedDateTime shanghaiTime = londonTime.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
4. ZoneId
/ ZoneOffset
------ 时区相关
类名 | 描述 | 常用方法 |
---|---|---|
ZoneId |
代表一个完整的时区(如 Asia/Shanghai ) |
of() 、systemDefault() |
ZoneOffset |
代表一个偏移量(如 +08:00 ) |
ofHours() 、UTC |
示例:
java
ZoneId zone = ZoneId.of("America/New_York");
ZoneOffset offset = ZoneOffset.of("+08:00");
5. Duration
/ Period
------ 时间差
类名 | 描述 | 单位 | 是否支持时区 |
---|---|---|---|
Duration |
时间差(精确到纳秒) | 秒、纳秒 | ❌ 否(基于 Instant ) |
Period |
日期差(精确到天) | 天、月、年 | ❌ 否 |
示例:
java
Duration duration = Duration.between(Instant.now(), Instant.now().plusSeconds(3600));
Period period = Period.between(LocalDate.now(), LocalDate.now().plusDays(5));
6. DateTimeFormatter
------ 格式化和解析
特性 | 描述 |
---|---|
是否支持时区? | ✅ 是(可通过 withZone() 设置) |
常用方法 | ofPattern(String) 、format(TemporalAccessor)、parse(CharSequence) |
推荐用途 | 格式化输出、解析字符串时间 |
示例:
java
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.of("UTC"));
String formatted = formatter.format(Instant.now());
🧾 总结对比表
API 类名 | 是否带时区 | 精度 | 推荐用途 | 是否线程安全 |
---|---|---|---|---|
Date |
❌ 否(实际是 UTC) | 毫秒 | 兼容旧代码 | ❌ |
Calendar |
✅ 是 | 毫秒 | 日期计算 | ❌ |
SimpleDateFormat |
✅ 是 | - | 格式化 | ❌ |
Instant |
❌ 否 | 纳秒 | 时间戳 | ✅ |
LocalDate / LocalTime / LocalDateTime |
❌ 否 | 天/小时/分钟 | 本地日期操作 | ✅ |
ZonedDateTime |
✅ 是 | 纳秒 | 带时区时间处理 | ✅ |
OffsetDateTime |
✅ 是 | 纳秒 | 固定偏移时间 | ✅ |
Duration |
❌ 否 | 纳秒 | 时间长度计算 | ✅ |
Period |
❌ 否 | 天/月/年 | 日期长度计算 | ✅ |
DateTimeFormatter |
✅ 是 | - | 格式化/解析 | ✅ |
✅ 推荐组合用法
场景 | 推荐 API 组合 |
---|---|
记录时间戳(日志、ID生成) | Instant |
显示给用户看的时间 | ZonedDateTime + DateTimeFormatter |
日期运算(如"明天"、"下周几") | LocalDate |
跨时区时间转换 | ZonedDateTime + withZoneSameInstant() |
时间差计算(精确到毫秒) | Duration |
日期差计算(按天、月) | Period |