430. Java 日期时间 API - 时间计算 Temporal 包

430. Java 日期时间 API - 时间计算 Temporal 包

今天我们要学习的是 java.time.temporal 包。它提供了一组 接口、类和枚举,专门用来支持日期和时间的底层操作,特别是各种 时间计算


1. 为什么需要 Temporal 包?

大家先想一个问题:
👉 我们平时用的 LocalDateLocalDateTimeZonedDateTime 已经很强大了,为什么还要搞一个 Temporal 包?

答案是:这些类在底层 都遵循统一的接口(Temporal、TemporalAccessor 等),所以无论我们是加一天、减一小时、还是取出某个字段,都可以用 同一套规则来处理

这就像写代码时:

  • 大部分时候我们直接用 String(具体类)。
  • 但底层其实都实现了 CharSequence(接口)。

2. 核心接口

2.1 Temporal 和 TemporalAccessor

  • Temporal
    • 可读可写(支持加减时间)
    • 实现类:InstantLocalDateTimeZonedDateTime
    • 提供统一的时间计算方法,例如:plus()minus()
  • TemporalAccessor
    • 只读版本,只能获取值,不能修改。

👉 打个比方:

  • Temporal 就像一个 可以调表针的钟表
  • TemporalAccessor 就像一个 只能看时间的钟表

2.2 TemporalField 与 TemporalUnit

  • TemporalField:表示时间的“字段”
    • 例如:天、月、年、星期几
    • 具体实现:ChronoField 枚举
  • TemporalUnit:表示时间的“单位”
    • 例如:秒、分钟、小时、天、年
    • 具体实现:ChronoUnit 枚举

⚡ 举个例子:

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 → 一年中的第几季度

📌 示例:

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.SECONDS
  • ChronoUnit.MINUTES
  • ChronoUnit.DAYS
  • ChronoUnit.YEARS
  • ChronoUnit.MILLENNIA(千年 🚀)

⚠️ 但是!
不是所有类都支持所有单位。

📌 示例:

Instant instant = Instant.now();

// 检查是否支持“天”这个单位
boolean supported = instant.isSupported(ChronoUnit.YEARS);
System.out.println("Instant 是否支持按天操作? " + supported);  // false

为什么返回 false?
因为 Instant绝对时间点(机器时间),它只能理解秒、纳秒这些精确单位,但不懂“年”这种人类时间概念。


5. TemporalAmount —— 时间量

时间加减需要一个“数量”,由 TemporalAmount 接口定义。
常见实现类有:

  • Duration → 精确到秒/纳秒(适合机器时间)
  • Period → 年/月/日(适合人类日历)

📌 示例:

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 小时
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容