java.time 时间相关操作
·
java.time 包是 Java 8 引入的现代日期时间 API(JSR-310),在JDK 17中依然沿用, 设计清晰、不可变、线程安全,取代了老旧的 java.util.Date 和 Calendar。以下是其中最常用的核心类及其用途,适合日常开发使用:
✅ 一、核心日期时间类
| 类 | 说明 | 典型用途 |
|---|---|---|
LocalDateTime | 本地日期时间(无时区) | 表示如 2025-10-22T14:30:00,常用于日志、业务时间(不涉及时区) |
LocalDate | 仅日期(无时、无时区) | 如 2025-10-22,用于生日、订单日期等 |
LocalTime | 仅时间(无日期、无时区) | 如 14:30:45,用于闹钟、营业时间等 |
ZonedDateTime | 带时区的完整日期时间 | 如 2025-10-22T14:30:00+08:00[Asia/Shanghai],用于全球时间处理 |
Instant | 时间戳(UTC 时刻) | 表示从 Unix Epoch(1970-01-01T00:00:00Z)开始的纳秒数,用于系统时间、日志时间戳 |
💡
LocalDateTime≠Instant:前者是“本地视角”的时间(如“今天下午2点”),后者是“全球统一时刻”(如“UTC时间某毫秒”)。
✅ 二、时区与区域相关
| 类 | 说明 |
|---|---|
ZoneId | 表示时区,如 ZoneId.of("Asia/Shanghai") 或 ZoneId.systemDefault() |
ZoneOffset | 表示固定偏移量,如 +08:00(不包含夏令时规则) |
Clock | 提供对当前时间的访问,支持测试时 mock 时间 |
✅ 三、格式化与解析
| 类 | 说明 |
|---|---|
DateTimeFormatter | 用于格式化和解析日期时间字符串 ✅ 预定义常量: - ISO_LOCAL_DATE_TIME- ofPattern("yyyy-MM-dd HH:mm:ss") |
LocalDateTime now = LocalDateTime.now();
String text = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
LocalDateTime parsed = LocalDateTime.parse("2025/10/22 14:30",
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
✅ 四、时间段与周期
| 类 | 说明 | 示例 |
|---|---|---|
Duration | 表示时间量(基于秒/纳秒),用于机器时间差 | Duration.between(start, end) → 2小时30分 |
Period | 表示日历量(年/月/日),用于人类可读周期 | Period.between(birthDate, today) → 25年3个月 |
// 计算两个时间相差多少小时
Duration dur = Duration.between(LocalDateTime.now(), futureTime);
long hours = dur.toHours();
// 计算年龄
LocalDate birth = LocalDate.of(1990, 5, 15);
Period age = Period.between(birth, LocalDate.now());
System.out.println(age.getYears() + "岁");
✅ 五、时间单位(用于计算)
| 类 | 说明 |
|---|---|
ChronoUnit | 枚举类,表示时间单位(DAYS, HOURS, MINUTES, YEARS 等) |
long days = ChronoUnit.DAYS.between(date1, date2);
LocalDateTime nextWeek = now.plus(7, ChronoUnit.DAYS);
✅ 六、其他实用类
| 类 | 说明 |
|---|---|
Year, YearMonth, MonthDay | 表示部分日期 - YearMonth.of(2025, 10) → 2025年10月(适合信用卡有效期)- MonthDay.of(12, 25) → 每年12月25日(适合生日提醒) |
TemporalAdjusters | 提供高级日期调整器 如: firstDayOfMonth(), lastDayOfYear() |
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDate nextFriday = today.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
📌 使用建议总结
| 场景 | 推荐类 |
|---|---|
| 系统时间戳、日志时间 | Instant |
| 数据库 datetime 字段(无时区) | LocalDateTime |
| 用户生日、订单日期 | LocalDate |
| 全球会议时间、跨时区应用 | ZonedDateTime |
| 时间差(机器计算) | Duration |
| 年龄、日历周期 | Period |
| 格式化输出 | DateTimeFormatter |
| 时区处理 | ZoneId + ZonedDateTime |
❌ 避免使用的旧类(JDK 8+ 不推荐)
java.util.Datejava.util.Calendarjava.text.SimpleDateFormat(非线程安全!)
示例:完整常用操作
// 1. 当前时间
LocalDateTime now = LocalDateTime.now();
// 2. 指定时间
LocalDateTime dt = LocalDateTime.of(2025, 10, 22, 14, 30);
// 3. 加7天
LocalDateTime nextWeek = dt.plusDays(7);
// 4. 转时间戳
long timestamp = dt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
// 5. 格式化
String str = dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
// 6. 解析
LocalDateTime parsed = LocalDateTime.parse("2025-10-22 14:30",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
// 7. 计算相差天数
long days = ChronoUnit.DAYS.between(now, dt);
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") 默认不包含时区信息,因为它通常用于格式化 LocalDateTime(无时区)。若你想在格式化结果中带上时区,需要满足两个条件:
- 使用带时区的时间对象(如
ZonedDateTime或OffsetDateTime) - 在 pattern 中显式加入时区符号
✅ 正确做法:使用 ZonedDateTime + 时区 pattern
示例 1:显示时区 ID(如 Asia/Shanghai)
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
String result = zdt.format(formatter);
System.out.println(result);
// 输出:2025-10-22 10:30:45 CST (或 Asia/Shanghai,取决于系统)
z表示 时区名称(如CST,PST,GMT),但可能不显示完整 ID。
示例 2:显示完整时区 ID(推荐用于日志或调试)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
String result = zdt.format(formatter);
System.out.println(result);
// 输出:2025-10-22 10:30:45 Asia/Shanghai
VV表示 时区 ID(ZoneId),如Asia/Shanghai、Europe/London(至少需要两个 V)
示例 3:显示 UTC 偏移量(如 +08:00)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
String result = zdt.format(formatter);
System.out.println(result);
// 输出:2025-10-22 10:30:45 +08:00
常用偏移 pattern:
X→+08XX→+0800XXX→+08:00(最常用)
⚠️ 重要:不能对 LocalDateTime 使用时区 pattern!
LocalDateTime ldt = LocalDateTime.now();
// ❌ 错误!LocalDateTime 没有时区,会抛异常
ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV")); // DateTimeException
✅ 必须先转为带时区对象:
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
String s = zdt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX"));
✅ 推荐组合(根据需求选择)
| 需求 | Pattern | 示例输出 |
|---|---|---|
| 显示偏移量(通用) | "yyyy-MM-dd HH:mm:ss XXX" | 2025-10-22 10:30:45 +08:00 |
| 显示完整时区 ID | "yyyy-MM-dd HH:mm:ss VV" | 2025-10-22 10:30:45 Asia/Shanghai |
| ISO 8601 标准格式 | DateTimeFormatter.ISO_ZONED_DATE_TIME | 2025-10-22T10:30:45+08:00[Asia/Shanghai] |
🔁 反向:带时区字符串解析
String text = "2025-10-22 10:30:45 +08:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
// 解析为 OffsetDateTime(推荐)
OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
// 或转为 ZonedDateTime
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Asia/Shanghai"));
注意:用
ZonedDateTime.parse()需要 pattern 包含 zone ID(如VV),否则建议先用OffsetDateTime。
总结
| 目标 | 正确方式 |
|---|---|
| 格式化带时区时间 | 用 ZonedDateTime / OffsetDateTime + pattern 含 XXX 或 VV |
从 LocalDateTime 加时区 | 先 .atZone(ZoneId) 转为 ZonedDateTime |
| 解析带时区字符串 | 用 OffsetDateTime.parse() + 对应 pattern |
public static void main(String[] args) {
long ts = Instant.now().toEpochMilli();
System.out.println(ts);
String result = Instant.ofEpochMilli(ts)
.atZone(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(result);
LocalDateTime start = LocalDateTime.of(2025, 1, 1, 0, 0);
LocalDateTime end = LocalDateTime.now();
long days = ChronoUnit.DAYS.between(start, end);
System.out.println(days);
LocalDateTime now = LocalDateTime.now();
LocalDateTime tomorrow = now.plusDays(1);
LocalDateTime oneHourAgo = now.minusHours(1);
System.out.println(tomorrow);
System.out.println(oneHourAgo);
ZonedDateTime now1 = ZonedDateTime.now();
String format = now1.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV"));
System.out.println(now1);
System.out.println(format);
}

更多推荐



所有评论(0)