duration处理基于秒/纳秒的线性时间量,适用于耗时计算;period处理基于年/月/日的日历跨度,适用于自然日期差。

掌握 Duration 与 Period 的关键,在于理解它们各自处理的“维度”不同:Duration 管的是钟表上的秒和纳秒,Period 管的是日历上的年、月、日。
看计算目标:问“过了多少秒/分钟”,还是“隔了几岁几个月”
如果问题关注耗时、延迟、执行时间——比如接口响应花了多少毫秒、任务运行了多长时间,就用 Duration。它返回的是线性、固定长度的时间量,1 小时永远是 3600 秒,不随闰秒或夏令时变化。
如果问题关注自然日期跨度——比如用户年龄、合同有效期、两个生日之间差几年几月,就用 Period。它的结果依赖日历规则:2024 年 1 月 31 日加一个月是 2 月 29 日(闰年),而 2025 年 1 月 31 日加一个月则是 2 月 28 日。
- Duration.between(Instant.ofEpochSecond(0), Instant.now()) → 得到精确到纳秒的总流逝时间
- Period.between(LocalDate.of(1990, 5, 15), LocalDate.now()) → 得到“35 年 11 个月 1 天”这类可读性强的结构化结果
看输入类型:必须匹配对应的时间/日期载体
Duration 只接受含时间信息的对象:Instant、LocalDateTime、ZonedDateTime、LocalTime。传入 LocalDate 会直接抛 UnsupportedTemporalTypeException,因为它没有“时分秒”,无法换算成纳秒。
Period 只接受纯日期对象:LocalDate、YearMonth。传入 LocalDateTime 会静默丢弃时间部分,只比对日期字段——容易造成逻辑偏差,比如 2024-01-01T23:59 和 2024-01-02T00:01 算出来仍是 P1D,不是你直觉以为的“差两分钟”。
- 想用 LocalDate 算 Duration?先转成当天零点的 LocalDateTime:
localDate.atStartOfDay() - 想用 LocalDateTime 算 Period?显式剥离时间:
time1.toLocalDate()和time2.toLocalDate()
看输出需求:要整数截断值,还是要可读字段组合
Duration 提供 toSeconds()、toMinutes()、toHours() 等方法,但注意这些返回的是向下取整的 long 值(如 2.9 小时 → toHours() == 2)。需要小数精度时,得用 toNanos() 自行换算。
Period 不提供“总天数”之类的一体化数值方法;它把结果拆成 getYears()、getMonths()、getDays() 三个独立字段,需组合使用。它也不支持跨单位换算(比如“把 1 年转成多少天”),因为月份天数不固定。
- Duration d = Duration.ofHours(2).plusMinutes(30); d.toMinutes() → 150
- Period p = Period.ofYears(1).plusMonths(2).plusDays(5); p.getYears()==1, p.getMonths()==2, p.getDays()==5
别混淆底层模型:一个是“尺子”,一个是“日历翻页”
Duration 是一把刻着纳秒刻度的尺子:两端一量,差多少就是多少,不管今天是不是夏令时切换日。即使跨越 DST 跳变(比如凌晨 2 点跳到 3 点),它仍按真实流逝的纳秒数算。
Period 是在日历上翻页:它模拟人类加减日期的行为。“加一个月”不是加 30 天,而是把月份数字+1,再按当月实际天数调整日期(如 1 月 31 日 +1 月 → 2 月 28 日或 29 日)。
- Duration.between(LocalDateTime.of(2025, 3, 30, 1, 0), LocalDateTime.of(2025, 3, 30, 3, 0)) → PT2H(严格 2 小时)
- Period.between(LocalDate.of(2025, 3, 30), LocalDate.of(2025, 5, 30)) → P2M(正好两个月,不关心中间有多少天)










