文档

Java™ 教程-Java Tutorials 中文版
Period 和 Duration
Trail: Date Time
Lesson: Standard Calendar

Period 和 Duration

编写代码以指定时间量时,请使用最符合你需要的类或方法:Duration 类,Period 类,或 ChronoUnit.between 方法。Duration 使用基于时间的值(秒,纳秒)测量时间量。Period 使用基于日期的值(年,月,日)。


注意: 一天的 Duration 正好时 24 小时。一天的 Period,当添加到 ZonedDateTime 时,可能会根据时区而有所不同。例如,如果它发生在夏令时的第一天或最后一天。

Duration

Duration 最适合测量基于机器的时间的情况,例如使用 Instant 对象的代码。Duration 对象以秒或纳秒为单位测量,并且不使用基于日期的构造,例如年,月和日,尽管该类提供了转换为天,小时和分钟的方法。如果 Duration 是使用在起点之前发生的终点创建的,则可以具有负值。

以下代码以纳秒为单位计算两个时刻之间的持续时间:

Instant t1, t2;
...
long ns = Duration.between(t1, t2).toNanos();

以下代码为 Instant 添加 10 秒:

Instant start;
...
Duration gap = Duration.ofSeconds(10);
Instant later = start.plus(gap);

Duration 未连接到时间线,因为它不跟踪时区或夏令时。将 Duration 等于 1 天添加到 ZonedDateTime 会导致正好 24 小时的添加,无论夏令时或其他可能导致的时间差异如何。

ChronoUnit

The Temporal Package 中讨论的 ChronoUnit 枚举定义了用于测量时间的单位。当你想要仅在单个时间单位(例如天或秒)中测量时间量时,ChronoUnit.between 方法非常有用。between 适用于所有基于时间的对象,但它仅返回单个单位中的数量。以下代码计算两个时间戳之间的间隔(以毫秒为单位):

import java.time.Instant;
import java.time.temporal.Temporal;
import java.time.temporal.ChronoUnit;

Instant previous, current, gap;
...
current = Instant.now();
if (previous != null) {
    gap = ChronoUnit.MILLIS.between(previous,current);
}
...

Period

要使用基于日期的值(年,月,日)定义时间量,请使用 Period 类。Period 类提供各种 get 方法,例如 getMonthsgetDaysgetYears,以便你可以从期间中提取时间。

总时间段由所有三个单元一起表示:月,日和年。要显示在单个时间单位(例如天)中测量的时间量,你可以使用 ChronoUnit.between 方法。

假设你出生于 1960 年 1 月 1 日,以下代码报告你的年龄。Period 类用于确定年,月和日的时间。使用 ChronoUnit.between 方法确定同一时段(总天数),并显示在括号中:

LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);

Period p = Period.between(birthday, today);
long p2 = ChronoUnit.DAYS.between(birthday, today);
System.out.println("You are " + p.getYears() + " years, " + p.getMonths() +
                   " months, and " + p.getDays() +
                   " days old. (" + p2 + " days total)");

代码生成类似于以下内容的输出:

You are 53 years, 4 months, and 29 days old. (19508 days total)

要计算到下一个生日的时间,你可以使用 Birthday 示例中的以下代码。Period 类用于确定以月和日为单位的值。ChronoUnit.between 方法返回总天数值,并显示在括号中。

LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);

LocalDate nextBDay = birthday.withYear(today.getYear());

//If your birthday has occurred this year already, add 1 to the year.
if (nextBDay.isBefore(today) || nextBDay.isEqual(today)) {
    nextBDay = nextBDay.plusYears(1);
}

Period p = Period.between(today, nextBDay);
long p2 = ChronoUnit.DAYS.between(today, nextBDay);
System.out.println("There are " + p.getMonths() + " months, and " +
                   p.getDays() + " days until your next birthday. (" +
                   p2 + " total)");

代码生成类似于以下内容的输出:

There are 7 months, and 2 days until your next birthday. (216 total)

这些计算不考虑时区差异。例如,如果你出生在澳大利亚,但目前住在班加罗尔,这会略微影响你确切年龄的计算。在这种情况下,将 PeriodZonedDateTime 类结合使用。将 Period 添加到 ZonedDateTime 时,会观察到时间差。


Previous page: Temporal Query
Next page: Clock