79

Duration在 Java 8 及更高版本中可用的新JSR 310日期 API(java.time 包)中的类中,javadoc 说:

此类以秒和纳秒为单位对时间量或时间量进行建模。可以使用其他基于持续时间的单位来访问它,例如分钟和小时。此外,可以使用 DAYS 单位并将其视为完全等于 24 小时,从而忽略夏令时的影响。

那么,为什么下面的代码会崩溃?

Duration duration = Duration.ofSeconds(3000);
System.out.println(duration.get(ChronoUnit.MINUTES));

这引发了一个UnsupportedTemporalTypeException

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes
    at java.time.Duration.get(Duration.java:537)

那么从持续时间对象中提取分钟和小时的推荐方法是什么?我们是否必须自己根据秒数进行计算?为什么以这种方式实施?

4

6 回答 6

106

“为什么要这样实施?”

其他答案涉及toXxx()允许查询小时/分钟的方法。我会尝试处理原因。

TemporalAmount接口和方法是在过程的get(TemporalUnit)后期添加的。我个人并不完全相信我们有足够的证据证明在该领域进行设计的正确方法,但稍微有点扭曲地添加TemporalAmount. 我相信这样做我们稍微混淆了 API。

事后看来,我相信TemporalAmount包含正确的方法,但我相信get(TemporalUnit)应该有不同的方法名称。原因是它get(TemporalUnit)本质上是一种框架级别的方法——它不是为日常使用而设计的。不幸的是,方法名称get并没有暗示这一点,从而导致诸如调用get(ChronoUnit.MINUTES)on之类的错误Duration

因此,思考的方式get(TemporalUnit)是想象一个低级框架,将数量视为大小为 2的 a Map<TemporalUnit, Long>,键为和。DurationMapSECONDSNANOS

同样,Period从低级框架来看,它Map的大小为 3 - DAYSMONTHS并且YEARS(幸运的是,出错的可能性较小)。

总的来说,应用程序代码的最佳建议是忽略方法get(TemporalUnit)。使用getSeconds(),getNano()toHours()代替toMinutes()

最后,从 a 获取 "hh:mm:ss" 的一种Duration方法是:

LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss"))

一点也不漂亮,但它确实可以持续不到一天的时间。

to…PartJava 9 中的新方法

JDK-8142936问题现在在 Java 9 中实现,添加了以下方法来访问Duration.

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart
于 2014-06-30T22:46:43.167 回答
37

文档说:

这将为两个支持的单位 SECONDS 和 NANOS 中的每一个返回一个值。所有其他单位都会抛出异常。

所以,最好的猜测答案——这就是他们设计的方式。

您可以使用其他一些方法在数小时内获得它:

long hours = duration.toHours();

分钟

long minutes = duration.toMinutes();
于 2014-06-30T13:52:55.097 回答
12

要以“标准化”方式获取小时/分钟/秒分量,您需要手动计算它们 - 下面的代码基本上是从Duration#toString方法中复制的:

Duration duration = Duration.ofSeconds(3000);
long hours = duration.toHours();
int minutes = (int) ((duration.getSeconds() % (60 * 60)) / 60);
int seconds = (int) (duration.getSeconds() % 60);
System.out.println(hours + ":" + minutes + ":" + seconds);
于 2014-06-30T15:52:02.263 回答
11

我想添加到 bigt 的答案 (+1),指出有用toHourstoMinutes和其他转换方法。持续时间规范说:

此类以秒和纳秒为单位对时间量或时间量进行建模。[...]

持续时间的范围需要存储一个大于 long 的数字。为了实现这一点,该类存储了一个表示秒的 long 和一个表示纳秒的 int,它始终在 0 到 999,999,999 之间。

有多种getter方法,例如getSecondsgetNanoget(TemporalUnit)。鉴于持续时间表示为 (seconds, nanos) 对,很明显为什么get(TemporalUnit)仅限于 seconds 和 nanos。这些 getter 方法直接从持续时间实例中提取数据并且是无损的。

相比之下,有多种 to-method 包括toDays, toHours, toMillis toMinutes, 和对持续时间值toNanos进行转换。这些转换是有损的,因为它们涉及截断数据,或者如果持续时间值不能以请求的格式表示,它们可能会引发异常。

显然,get 方法无需转换即可提取数据,而 to 方法执行某种类型的转换,这显然是设计的一部分。

于 2014-06-30T19:19:18.240 回答
4

删除时间然后获取分钟

long hours = attendanceDuration.toHours(); long minutes = attendanceDuration.minusHours(hours).toMinutes();

于 2019-02-11T13:38:02.473 回答
-1

通过下面的代码,我得到了这个持续时间输出:

1天2小时5分钟

代码示例:

private String getDurationAsString(Duration duration)
{
    StringBuilder durationAsStringBuilder = new StringBuilder();
    if (duration.toDays() > 0)
    {
        String postfix = duration.toDays() == 1 ? "" : "s";
        durationAsStringBuilder.append(duration.toDays() + " day");
        durationAsStringBuilder.append(postfix);
    }

    duration = duration.minusDays(duration.toDays());
    long hours = duration.toHours();
    if (hours > 0)
    {
        String prefix = Utils.isEmpty(durationAsStringBuilder.toString()) ? "" : ", ";
        String postfix = hours == 1 ? "" : "s";
        durationAsStringBuilder.append(prefix);
        durationAsStringBuilder.append(hours + " hour");
        durationAsStringBuilder.append(postfix);
    }

    duration = duration.minusHours(duration.toHours());
    long minutes = duration.toMinutes();
    if (minutes > 0)
    {
        String prefix = Utils.isEmpty(durationAsStringBuilder.toString()) ? "" : ", ";
        String postfix = minutes == 1 ? "" : "s";
        durationAsStringBuilder.append(prefix);
        durationAsStringBuilder.append(minutes + " minute");
        durationAsStringBuilder.append(postfix);
    }

    return durationAsStringBuilder.toString();
}

说明

通过使用 Duration 界面,您可以轻松找到所需的确切字符串显示。您只需要从当前持续时间中减少更大的 TemporalUnit。

例如:

  1. 计算天数
  2. 从持续时间减少天数
  3. 计算小时数
  4. 从持续时间等中减少小时数......直到你得到持续时间= 0
于 2018-03-05T18:31:14.210 回答