1. 概述
本文将快速介绍Java 8引入的两个日期时间处理类:Period
和Duration
。这两个类都能表示时间量或计算日期差值,核心区别在于:
- ✅
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仓库