摘要:LocalDate startDate = LocalDate.of(2015, 2, 20);LocalDate endDate = LocalDate.of(2017, 1, 15);Period period = Period.between(start
在本文中让我们来看看在 Java 8 中引入的 2 个新的类: Period 和 Duration.
上面 2 个类可以被用来替换在 determine 和 time 中大量使用用来计算 2 个时间不同的 API。
针对上面 2 个类最主要的不同就是 Period 被用来计算日期的不同,Duration 则是被用来计算时间的不同。
Period 类
Period 使用的单位是 年,月,日来表达 2 个日期之间的不同。
我们可以通过 2 个时期之间不同的 between 方法来获得 Period 对象。
LocalDate startDate = LocalDate.of(2015, 2, 20);LocalDate endDate = LocalDate.of(2017, 1, 15);Period period = Period.between(startDate, endDate);当我们获得 Period 对象后,我们可以用 Period 对象中的 *getYears, getMonths, getDays 方法来获得具体的值。
logger.info(String.format("Years:%d months:%d days:%d", period.getYears, period.getMonths, period.getDays));isNegative 也是 Period 中的一个方法,可以通过这个方法来判断 2 个比较时间的大小关系。
当这个方法返回 True 的时候,表明结束时间要大于起始时间。
assertFalse(period.isNegative);相反的 isNegative 如果返回的为 false,那么表明 startDate* 要早入 endDate 的值。
另外一个可以创建 Period 对象的方法就是使用数字,Period 中提供了一个 of 方法,我们可以用这个方法来构造一个 Period 对象:
Period fromUnits = Period.of(3, 10, 10);Period fromDays = Period.ofDays(50);Period fromMonths = Period.ofMonths(5);Period fromYears = Period.ofYears(10);Period fromWeeks = Period.ofWeeks(40);assertEquals(280, fromWeeks.getDays);如果 of 方法中只有一个输入参数的话,那么默认调用的是 ofDays 方法,等于用输入的数字初始化日这个单位。,
基于上面的设计, ofWeeks 方法使用的是乘以 7 的方式,因为不管一年有多少天,但一周 7 天这个肯定是不会变的。
通过看 JDK 的源代码:
public static Period ofWeeks(int weeks) { return create(0, 0, Math.multiplyExact(weeks, 7)); }上面的构造方法就能说明这个问题了。
同时,还可以使用字符串来创建 Period 对象,这个字符串使用的序列为 “PnYnMnD”:
Period fromCharYears = Period.parse("P2Y");assertEquals(2, fromCharYears.getYears);Period fromCharUnits = Period.parse("P2Y3M5D");assertEquals(5, fromCharUnits.getDays);当 period 对象创建成功后,可以使用 plusX 和 minusX 方法来对创建的 period 对象中的值进行调整:
assertEquals(56, period.plusDays(50).getDays);assertEquals(9, period.minusMonths(2).getMonths);Duration 类
和 Period 相对,Duration 类是对时间进行操作的。
具体操作的单位为秒(seconds )和纳秒(nanoseconds )。
因可以直接对纳秒进行操作,所以 Duration 能比较精确的对时间进行计算。
另外,要获得 Duration 对象,我们需要从 instants 来进行比较,使用 between 方法来比较 instants 。
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);上面的方法能够构造一个 Duration 对象,然后从 Duration 对象中使用 getSeconds 或者getNanoseconds 方法来获得具体的单位值:
assertEquals(60, duration.getSeconds);可选的,因为是对时间进行计算机,那么你还可以从 LocalDateTime 实例中来比较构造一个 Duration 对象:
LocalDateTime start = LocalDateTime.parse("2020-01-01T08:00:00");LocalDateTime end = LocalDateTime.parse("2023-01-01T12:00:00");Duration.between(start, end).getSeconds;基于起始时间的不同,Duration 可能会有下面的 3 中情况:
Negative: start
Zero: start = end
Positive: start > end
同时,标准的时间 Time API 也提供了转发方法来检查 Duration 是否为 0 或者负数:
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);LocalDateTime theTime = LocalDateTime.parse("2023-09-09T08:00:00");assertTrue(Duration.between(theTime,theTime).isZero);assertFalse(Duration.between(theTime,theTime).isNegative);// Java version 18+ requiredLocalDateTime start = LocalDateTime.parse("2020-01-01T08:00:00");LocalDateTime end = LocalDateTime.parse("2020-01-01T12:00:00");assertTrue(Duration.between(start, end).isPositive);assertFalse(Duration.between(end, start).isPositive);当然,我们也可以使用单位来构造一个 Duration 对象,这个和 Period 的构造方法基本相同。
可以使用的方法有: ofDays, ofHours, ofMillis, ofMinutes, ofNanos, ofSeconds:
Duration fromDays = Duration.ofDays(1);assertEquals(86400, fromDays.getSeconds); Duration fromMinutes = Duration.ofMinutes(60);我们还可以使用字符串的方法来构造 Duration ,表达方式为:PnDTnHnMn.nS:
Duration fromChar1 = Duration.parse("P1DT1H10M10.5S");Duration fromChar2 = Duration.parse("PT10M");duration 对象也可以实现其他单位的转换,使用的方法为:toDays, toHours, toMillis, toMinutes:
assertEquals(1, fromMinutes.toHours);针对时间的增加和减少,我们可以使用 plusX 方法 minusX, X 根据具体的单位不同而使用不同的字符来表达,具体的可以参考 JDK API 的手册。
下面我们只简单的列了几个可以使用的方法:
assertEquals(120, duration.plusSeconds(60).getSeconds); assertEquals(30, duration.minusSeconds(30).getSeconds);为了避免书写上面的问题,我们还可以在 plus 和 minus 方法中使用 ChronoUnit 来制定添加或者减少的单位:
assertEquals(120, duration.plus(60, ChronoUnit.SECONDS).getSeconds); assertEquals(30, duration.minus(30, ChronoUnit.SECONDS).getSeconds);结论
让我为你总结一下这两个类的主要区别和用法:
Period 和 Duration 的主要区别
Period
使用基于日期的值(date-based values)
主要用于处理年、月、日的时间段
适用于较长时间段的计算
Duration
使用基于时间的值(time-based values)
主要用于处理秒和纳秒级别的时间
适用于更短、更精确的时间间隔
Period 的主要用法
创建 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); // 年、月、日Period fromDays = Period.ofDays(50);Period fromMonths = Period.ofMonths(5);Period fromYears = Period.ofYears(10);Period fromWeeks = Period.ofWeeks(40);解析字符串创建 Period:
Period fromCharYears = Period.parse("P2Y"); // 2年Period fromCharUnits = Period.parse("P2Y3M5D"); // 2年3月5日Duration 的主要用法
创建 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);// 直接创建特定时长Duration fromDays = Duration.ofDays(1);Duration fromMinutes = Duration.ofMinutes(60);Duration 的其他操作:
// 检查 Duration 的性质duration.isNegative;duration.isZero;duration.isPositive; // Java 18+// 转换到其他时间单位duration.toDays;duration.toHours;duration.toMillis;duration.toMinutes;// 增加或减少时长duration.plusSeconds(60);duration.minusSeconds(30);这两个类都是在 #Java#8 中引入的,属于新的日期时间 API 的一部分,它们提供了更清晰和更易用的时间间隔处理方式。
来源:妖精动漫