在Java中Period和Duration有什么区别_Java时间间隔计算解析

Period用于日历语义(年月日),如生日、工龄;Duration用于精确时间量(秒/毫秒),如接口耗时、定时器。二者不可混用,否则抛DateTimeException或结果错误。

PeriodDuration 看似都算“时间差”,但它们根本不是同一类东西——一个管“日历上的日期怎么变”,一个管“钟表上的秒针走了多

久”。用错类型,轻则结果错得离谱(比如把 1 月 31 日加 Period.ofMonths(1) 得到 2 月 31 日再自动折成 3 月 3 日),重则直接抛 DateTimeException


什么时候必须用 Period?——只跟年/月/日打交道时

当你在处理生日、工龄、合同起止日、法定节假日间隔等「人类日历语义」问题时,Period 是唯一正解。

  • Period.between(LocalDate.of(2025, 1, 31), LocalDate.of(2025, 3, 31)) 返回 P2M(2个月),它知道 2 月只有 29 天,不硬算天数
  • LocalDate.now().plus(Period.ofYears(1)) 会智能跳到明年同月同日(哪怕那天不存在,也会按日历规则调整)
  • 不能传 LocalDateTimeInstantPeriod.between(),否则编译不报错但运行时抛 DateTimeException
  • Period.parse("P1Y2M3D") 支持 ISO-8601 字符串解析,但注意:它不接受带时间部分的字符串(如 "P1Y2MT3H" 是非法的)
LocalDate start = LocalDate.of(2025, 1, 31);
LocalDate end = start.plus(Period.ofMonths(1)); // → 2025-02-28(不是 2025-02-31)
System.out.println(end);

什么时候必须用 Duration?——只跟秒/毫秒/纳秒精度有关时

当你在测接口耗时、计算任务执行时长、做定时器倒计时、或和数据库 INTERVAL 类型交互时,Duration 才是真·时间尺子。

  • Duration.between(LocalTime.NOON, LocalTime.of(14, 30)) 返回 PT2H30M,精确到纳秒,不关心哪年哪月
  • Duration.ofDays(1) 永远是 86400 秒,不管这天是不是闰秒日;而 Period.ofDays(1) 只是“日历上过一天”,不承诺多少秒
  • LocalDateDuration.between() 会直接炸:抛 DateTimeException: Unsupported unit: Seconds
  • DurationtoString() 输出如 PT8H6M12.345S,开头 PT 表示“Period Time”,别被名字骗了——它和 Period 没半毛钱关系
LocalDateTime start = LocalDateTime.of(2026, 1, 19, 10, 0);
LocalDateTime end = LocalDateTime.of(2026, 1, 19, 12, 30, 45, 123_000_000);
Duration d = Duration.between(start, end);
System.out.println(d.toMinutes());   // → 150
System.out.println(d.toNanos());     // → 9045123000000

最容易踩的坑:混用类型 + 误读 between() 参数顺序

两个类的 between() 都是「第二个参数减第一个参数」,但方向感一错,结果就全反了——而且 isNegative() 不是万能补丁。

  • Period.between(d1, d2):如果 d1d2 后面,返回负值(getDays() 为负),但 plus() 仍按正逻辑加,容易绕晕
  • Duration.between(t1, t2) 同理:若 t1 晚于 t2,得到负 DurationtoSeconds() 返回负数,但没人想在日志里写“耗时 -120 秒”
  • 别试图用 Duration 算年龄:它不会处理“2026 年 1 月 19 日减 1990 年 5 月 12 日等于多少年”,因为年不是固定秒数
  • Android 开发者注意:Duration 需 API 26+,低版本要用 ThreeTenABP 兼容库,而 Period 同样受限

真正要记住的只有一条:日期变化看日历(用 Period),时间流逝看秒表(用 Duration
其余所有异常、错位、负值,几乎都源于没守住这条线。