文章目录
- [430. Java 日期时间 API - 时间计算 Temporal 包](#430. Java 日期时间 API - 时间计算 Temporal 包)
-
- [1. 为什么需要 Temporal 包?](#1. 为什么需要 Temporal 包?)
- [2. 核心接口](#2. 核心接口)
-
- [2.1 Temporal 和 TemporalAccessor](#2.1 Temporal 和 TemporalAccessor)
- [2.2 TemporalField 与 TemporalUnit](#2.2 TemporalField 与 TemporalUnit)
- [3. ChronoField 和 IsoFields](#3. ChronoField 和 IsoFields)
- [4. ChronoUnit ------ 时间单位](#4. ChronoUnit —— 时间单位)
- [5. TemporalAmount ------ 时间量](#5. TemporalAmount —— 时间量)
- [6. 小结 🎯](#6. 小结 🎯)
430. Java 日期时间 API - 时间计算 Temporal 包
今天我们要学习的是 java.time.temporal 包。它提供了一组 接口、类和枚举 ,专门用来支持日期和时间的底层操作,特别是各种 时间计算。
1. 为什么需要 Temporal 包?
大家先想一个问题:
👉 我们平时用的 LocalDate、LocalDateTime、ZonedDateTime 已经很强大了,为什么还要搞一个 Temporal 包?
答案是:这些类在底层 都遵循统一的接口(Temporal、TemporalAccessor 等) ,所以无论我们是加一天、减一小时、还是取出某个字段,都可以用 同一套规则来处理。
这就像写代码时:
- 大部分时候我们直接用
String(具体类)。 - 但底层其实都实现了
CharSequence(接口)。
2. 核心接口
2.1 Temporal 和 TemporalAccessor
Temporal- 可读可写(支持加减时间)
- 实现类:
Instant、LocalDateTime、ZonedDateTime等 - 提供统一的时间计算方法,例如:
plus()、minus()
TemporalAccessor- 只读版本,只能获取值,不能修改。
👉 打个比方:
Temporal就像一个 可以调表针的钟表。TemporalAccessor就像一个 只能看时间的钟表。
2.2 TemporalField 与 TemporalUnit
TemporalField:表示时间的"字段"- 例如:天、月、年、星期几
- 具体实现:
ChronoField枚举
TemporalUnit:表示时间的"单位"- 例如:秒、分钟、小时、天、年
- 具体实现:
ChronoUnit枚举
⚡ 举个例子:
java
LocalDate date = LocalDate.now();
// 取出当年的第几天
int dayOfYear = date.get(ChronoField.DAY_OF_YEAR);
System.out.println("今天是今年的第 " + dayOfYear + " 天");
// 取出第几季度(IsoFields 提供)
int quarter = date.get(IsoFields.QUARTER_OF_YEAR);
System.out.println("现在是第 " + quarter + " 季度");
3. ChronoField 和 IsoFields
ChronoField
提供了大量常用的日期时间字段,例如:DAY_OF_YEAR→ 一年中的第几天CLOCK_HOUR_OF_DAY→ 一天中的第几小时(1-24)MINUTE_OF_HOUR→ 当前小时的第几分钟
IsoFields
补充了一些 ISO-8601 规范里的字段,比如:QUARTER_OF_YEAR→ 一年中的第几季度
📌 示例:
java
LocalDate today = LocalDate.now();
// 检查 LocalDate 是否支持 "小时" 字段
boolean isSupported = today.isSupported(ChronoField.CLOCK_HOUR_OF_DAY);
System.out.println("LocalDate 是否支持小时字段? " + isSupported); // false
// 获取毫秒数(通过 ChronoField)
LocalTime time = LocalTime.now();
int millis = time.get(ChronoField.MILLI_OF_SECOND);
System.out.println("当前毫秒数: " + millis);
// 获取季度(通过 IsoFields)
int q = today.get(IsoFields.QUARTER_OF_YEAR);
System.out.println("当前季度: Q" + q);
4. ChronoUnit ------ 时间单位
ChronoUnit 是时间单位的标准枚举,从 纳秒 到 千年 ,都有定义。
比如:
ChronoUnit.SECONDSChronoUnit.MINUTESChronoUnit.DAYSChronoUnit.YEARSChronoUnit.MILLENNIA(千年 🚀)
⚠️ 但是!
不是所有类都支持所有单位。
📌 示例:
java
Instant instant = Instant.now();
// 检查是否支持"天"这个单位
boolean supported = instant.isSupported(ChronoUnit.YEARS);
System.out.println("Instant 是否支持按天操作? " + supported); // false
为什么返回 false?
因为 Instant 是 绝对时间点(机器时间),它只能理解秒、纳秒这些精确单位,但不懂"年"这种人类时间概念。
5. TemporalAmount ------ 时间量
时间加减需要一个"数量",由 TemporalAmount 接口 定义。
常见实现类有:
Duration→ 精确到秒/纳秒(适合机器时间)Period→ 年/月/日(适合人类日历)
📌 示例:
java
LocalDate today = LocalDate.now();
// 用 Period 加 1 个月
LocalDate nextMonth = today.plus(Period.ofMonths(1));
System.out.println("一个月后: " + nextMonth);
// 用 Duration 加 1 小时
LocalDateTime now = LocalDateTime.now();
LocalDateTime oneHourLater = now.plus(Duration.ofHours(1));
System.out.println("一小时后: " + oneHourLater);
6. 小结 🎯
| 概念 | 接口/类 | 举例 |
|---|---|---|
| 时间对象 | Temporal, TemporalAccessor |
LocalDate, Instant |
| 时间字段 | TemporalField, ChronoField |
DAY_OF_YEAR, CLOCK_HOUR_OF_DAY |
| 时间单位 | TemporalUnit, ChronoUnit |
SECONDS, DAYS, MILLENNIA |
| 时间量 | TemporalAmount, Period, Duration |
Period.ofMonths(1), Duration.ofHours(2) |
✅ 记忆方法:
- Field → 字段(是什么) → 年、月、日
- Unit → 单位(以什么度量) → 天、小时、秒
- Amount → 时间量(加减多少) → 3 天、2 小时