Period用于日历周期计算,如年月日差值,按日历规则运算且不支持时分秒;Duration用于精确时间差值,基于纳秒的时间轴差,不涉日历。

Period适合处理年月日这种日历周期
当你需要计算两个LocalDate之间相差多少年、月、日(比如“入职满3年6个月”),用Period才对。它按日历规则运算:2023-01-31 到 2024-03-15 会算出 P1Y1M15D,而不是简单加总天数。
常见错误是拿Period去减LocalDateTime或Instant——它不支持时分秒,会抛UnsupportedTemporalTypeException。
-
Period.between(LocalDate.of(2022, 1, 15), LocalDate.of(2024, 4, 20))→P2Y3M5D - 不能用于带时区或纳秒精度的时间类型
- 加减操作只影响年/月/日字段,不自动归一化(比如
P13M不会自动转成P1Y1M,需手动调用normalized())
Duration适合处理精确的秒和纳秒差值
当你关心的是“耗时多少毫秒”“任务执行了12.3秒”,就该用Duration。它基于时间轴上的绝对差值,单位是纳秒,和日历无关。
典型误用是用Duration.between()传入两个LocalDate——结果永远是0,因为LocalDate没有时间信息,Duration无法提取有效时间点。
立即学习“Java免费学习笔记(深入)”;
-
Duration.between(Instant.now(), Instant.now().plusSeconds(5))→PT5S - 支持
Instant、LocalTime、OffsetTime等带时间刻度的类型 -
Duration.ofDays(1)实际是86400秒,不是“按日历跳一天”,所以跨夏令时可能和预期不符
别混用,也别试图互相转换
Period和Duration语义不同,没有通用换算方式。1个月不等于固定秒数,闰年、月末、夏令时都会影响结果。
有人想用Period.toTotalMonths() * 30L * 24 * 3600硬转成Duration,这在业务逻辑里极不可靠——2月只有28天,7月有31天,而且没考虑时区偏移。
- 需要“从今天起30天后” → 用
LocalDate.plus(Period.ofDays(30)) - 需要“从现在起30天的毫秒数” → 用
Duration.ofDays(30),但注意这是固定86400×30秒,不是日历意义上的30天 - 如果必须桥接(如定时任务延迟),优先用
ZonedDateTime做中间转换,而不是强转Period/Duration
实际项目里最容易被忽略的一点
很多人写测试时用Period.ofDays(1)模拟“明天”,但在跨月或跨年边界(比如1月31日+1天)会触发DateTimeException,因为Period加法依赖目标日期是否合法。而Duration.ofDays(1)加到Instant上永远不会失败,但也不代表日历上的“明天”。
真正安全的做法是:明确你操作的是日历日期(用LocalDate+Period),还是时间轴偏移(用Instant+Duration),不要指望一个类能同时满足两者。










