1. 概述

本文将快速介绍Java 8引入的两个日期时间处理类:PeriodDuration。这两个类都能表示时间量或计算日期差值,核心区别在于:

  • Period:基于日期单位(年/月/日)
  • Duration:基于时间单位(秒/纳秒)

2. Period类详解

Period使用年、月、日表示时间段,适合处理日期相关的计算。

2.1 创建Period对象

通过日期差值创建

LocalDate startDate = LocalDate.of(2015, 2, 20);
LocalDate endDate = LocalDate.of(2017, 1, 15);

Period period = Period.between(startDate, endDate);

通过时间单位创建

Period fromUnits = Period.of(3, 10, 10);  // 3年10月10天
Period fromDays = Period.ofDays(50);      // 50天
Period fromMonths = Period.ofMonths(5);   // 5个月
Period fromYears = Period.ofYears(10);    // 10年
Period fromWeeks = Period.ofWeeks(40);    // 40周(自动换算为280天)

通过字符串解析创建(格式:PnYnMnD):

Period fromCharYears = Period.parse("P2Y");        // 2年
Period fromCharUnits = Period.parse("P2Y3M5D");    // 2年3月5天

2.2 常用操作

获取时间分量

LOG.info("Years:" + period.getYears() + 
  " months:" + period.getMonths() + 
  " days:"+period.getDays());

判断时间方向

assertFalse(period.isNegative());  // endDate > startDate时返回false

时间增减

assertEquals(56, period.plusDays(50).getDays());   // 增加50天
assertEquals(9, period.minusMonths(2).getMonths()); // 减少2个月

⚠️ 注意:ofWeeks()会自动将周转换为天(1周=7天)

3. Duration类详解

Duration表示秒或纳秒级的时间间隔,适合处理需要高精度的短时间计算。

3.1 创建Duration对象

通过时间点差值创建

Instant start = Instant.parse("2017-10-03T10:15:30.00Z");
Instant end = Instant.parse("2017-10-03T10:16:30.00Z");
        
Duration duration = Duration.between(start, end);  // 60秒

通过LocalDateTime创建

LocalDateTime start = LocalDateTime.parse("2020-01-01T08:00:00");
LocalDateTime end = LocalDateTime.parse("2023-01-01T12:00:00");

Duration.between(start, end).getSeconds();  // 计算秒数差

通过时间单位创建

Duration fromDays = Duration.ofDays(1);      // 1天(86400秒)
Duration fromMinutes = Duration.ofMinutes(60); // 60分钟

通过字符串解析创建(格式:PnDTnHnMn.nS):

Duration fromChar1 = Duration.parse("P1DT1H10M10.5S"); // 1天1小时10分10.5秒
Duration fromChar2 = Duration.parse("PT10M");          // 10分钟

3.2 常用操作

时间方向判断

LocalDateTime start = LocalDateTime.parse("2020-01-01T08:00:00");
LocalDateTime end = LocalDateTime.parse("2020-01-01T12:00:00");

assertFalse(Duration.between(start, end).isNegative());  // 正向
assertTrue(Duration.between(end, start).isNegative());   // 负向
assertTrue(Duration.between(start, start).isZero());     // 零值

✅ Java 18+ 新增isPositive()方法:

// 需Java 18+
assertTrue(Duration.between(start, end).isPositive());  // 正向

时间单位转换

assertEquals(1, fromMinutes.toHours());  // 60分钟转换为1小时

时间增减

assertEquals(120, duration.plusSeconds(60).getSeconds());   // 增加60秒
assertEquals(30, duration.minusSeconds(30).getSeconds());   // 减少30秒

// 使用TemporalUnit精确控制
assertEquals(120, duration.plus(60, ChronoUnit.SECONDS).getSeconds());

4. 总结

特性 Period Duration
适用场景 日期计算(年/月/日) 精确时间计算(秒/纳秒)
精度 天级 纳秒级
创建方式 日期差值/单位指定/字符串 时间点差值/单位指定
典型用例 计算年龄、合同有效期 API响应时间、任务耗时

踩坑提醒:

  • ❌ 不要用Period处理小时/分钟级计算
  • ❌ 不要用Duration处理跨年/跨月的日期计算
  • ✅ 混合使用时注意单位转换(如1天=86400秒)

完整示例代码见GitHub仓库


原始标题:Period and Duration in Java