period是java 8表示日历年月日差值的不可变类,用于localdate间按日历单位计算(如p2y3m7d),不处理时区、时间部分或总天数,需配合chronounit.days.between()获取天数。

Period 是 Java 8 引入的用于表示“年-月-日”时间量的不可变类,适用于计算两个 LocalDate 之间以**日历单位**(而非精确毫秒)衡量的差值。它不考虑时区、时间部分,也不处理跨时区或带时间的日期(如 LocalDateTime 或 ZonedDateTime),因此使用前需明确:你关心的是“日历上的年月日变化”,比如“2023-01-15 到 2024-03-20 相差 1年2个月5天”,而不是总天数或毫秒数。
用 Period.between() 计算 LocalDate 之间的年月日
这是最常用、最直接的方式:
- 两个参数必须是
LocalDate类型(不能是LocalDateTime,否则编译报错); - 结果按“先年、再月、后日”的逻辑逐级计算(类似手动推算:先看年份差,再在同年份下看月份差,最后看同月下的日期差);
- 如果结束日期早于起始日期,返回的
Period中各字段为负值。
示例:
LocalDate end = LocalDate.of(2024, 8, 17);
Period period = Period.between(start, end);
System.out.println(period); // P2Y3M7D
System.out.println(period.getYears()); // 2
System.out.println(period.getMonths()); // 3
System.out.println(period.getDays()); // 7
注意:Period 不等于总天数,也不自动归一化
Period 的设计是“日历感知”的,不是“天数换算”。例如:
-
Period.between(LocalDate.of(2023, 1, 31), LocalDate.of(2023, 3, 3))得到P1M3D(1个月零3天),不是P0Y0M31D——因为 1 月有 31 天,但 2 月只有 28/29 天,Java 按实际日历滚动:1月31日 → 2月31日无效,自动转为3月3日; - 它不会把 13 个月自动转成 “1年1个月”,
Period.ofMonths(13)就是P13M,不会变成P1Y1M; - 如果你需要总天数,应改用
ChronoUnit.DAYS.between(start, end)。
不能直接用于 LocalDateTime 或 ZonedDateTime
Period.between() 只接受 LocalDate。若你有带时间的日期:
- 想忽略时间只比日期部分:先用
localDateTime.toLocalDate()提取日期; - 想保留时间影响(如跨天逻辑):
Period不适用,应改用Duration(针对小时/分钟/秒)或手动计算天数+解析年月日; - 涉及时区(如用户在纽约 vs 东京),需先统一为同一时区的
LocalDateTime或用ZonedDateTime配合ChronoUnit。
常见误区与建议
- 别用
Period做精确时间差(如“距离生日还有多少毫秒”),那是Duration或Instant的职责; - 不要假设
Period支持加减法能完全可逆(例如date.plus(period).minus(period)不一定等于原 date,尤其在月末边界如 1月31日 + 1月 ≠ 2月31日); - 如需格式化输出,可用
period.toString()(返回类似P2Y3M7D),或手动拼接:String.format("%d年%d月%d天", p.getYears(), p.getMonths(), p.getDays()); - 业务中若需“满一年才算一岁”等规则,
Period的自然行为通常符合预期,无需额外处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











