为什么我不能在 java.time 中获得以分钟或小时为单位的持续时间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24491243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:34:26  来源:igfitidea点击:

Why can't I get a duration in minutes or hours in java.time?

javajava-8java-time

提问by Pierre Henry

Of the Durationclass in the new JSR 310date API (java.time package) available in Java 8 and later, the javadoc says :

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

This class models a quantity or amount of time in terms of seconds and nanoseconds. It can be accessed using other duration-based units, such as minutes and hours.In addition, the DAYS unit can be used and is treated as exactly equal to 24 hours, thus ignoring daylight savings effects.

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

So, why does the following code crash ?

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

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

This raises an UnsupportedTemporalTypeException:

这引发了一个UnsupportedTemporalTypeException

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

So what is the recommended way to extract minutes and hours from a duration object ? Do we have to make the calculation ourselves from the number of seconds ? Why was it implemented that way ?

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

采纳答案by JodaStephen

"Why was it implemented that way?"

“为什么要这样实施?”

Other answers deal with the toXxx()methods that allow the hours/minutes to be queried. I'll try to deal with the why.

其他答案涉及toXxx()允许查询小时/分钟的方法。我会尽量解决为什么。

The TemporalAmountinterface and get(TemporalUnit)method was added fairly late in the process. I personally was not entirely convinced that we had enough evidence of the right way to work the design in that area, but was slightly arm-twisted to add TemporalAmount. I believe that in doing so we slightly confused the API.

TemporalAmount界面和get(TemporalUnit)方法的过程中较晚加入。我个人并不完全相信我们有足够的证据证明该领域的设计是正确的,但我有点不情愿地添加了TemporalAmount. 我相信这样做我们会稍微混淆 API。

In hindsight, I believe that TemporalAmountcontains the right methods, but I believe that get(TemporalUnit)should have had a different method name. The reason is that get(TemporalUnit)is essentially a framework-level method - it is not designed for day-today use. Unfortunately the method name getdoes not imply this, resulting in bugs like calling get(ChronoUnit.MINUTES)on Duration.

事后看来,我相信TemporalAmount包含正确的方法,但我相信get(TemporalUnit)应该有一个不同的方法名称。原因是它get(TemporalUnit)本质上是一种框架级方法——它不是为日常使用而设计的。不幸的是,方法的名称get并不意味着这一点,导致盲蝽象调用get(ChronoUnit.MINUTES)Duration

So, the way to think of get(TemporalUnit)is to imagine a low-level framework viewing the amount as a Map<TemporalUnit, Long>where Durationis a Mapof size two with keys of SECONDSand NANOS.

所以,想的办法get(TemporalUnit)是想象一个低层次的框架观看量为Map<TemporalUnit, Long>这里Duration是一个Map大小两次与中键SECONDSNANOS

In the same, way, Periodis viewed from the low-level frameworks as a Mapof size three - DAYS, MONTHSand YEARS(which fortunately has less chance of errors).

在是相同的,这样,Period从低级别的框架看作Map大小三- DAYSMONTHSYEARS(其幸好具有较少错误的几率)。

Overall, the best advice for application code is to ignore the method get(TemporalUnit). Use getSeconds(), getNano(), toHours()and toMinutes()instead.

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

Finally, one way to get "hh:mm:ss" from a Durationis to do:

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

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

Not pretty at all, but it does work for durations less than one day.

一点也不漂亮,但它的工作持续时间不到一天。

New to…Partmethods in Java 9

to…PartJava 9 中的新方法

JDK-8142936issue now implemented in Java 9, adding the following methods to access each part of a Duration.

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

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart
  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart

回答by blgt

The documentationsays:

文件说:

This returns a value for each of the two supported units, SECONDS and NANOS. All other units throw an exception.

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

So, best guess answer -- that's the way they designed it.

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

You can use some of the other methods to get it in hours:

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

long hours = duration.toHours();

or minutes:

分钟

long minutes = duration.toMinutes();

回答by assylias

To get the hour/minute/second components in a "normalised" way, you need to calculate them manually - the code below is essentially copied from the Duration#toStringmethod:

要以“标准化”的方式获取小时/分钟/秒分量,您需要手动计算它们 - 下面的代码基本上是从该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);

回答by Stuart Marks

I'd like to add to bigt's answer (+1) that pointed out the useful toHours, toMinutesand other conversion methods. The Duration specificationsays:

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

This class models a quantity or amount of time in terms of seconds and nanoseconds. [...]

The range of a duration requires the storage of a number larger than a long. To achieve this, the class stores a long representing seconds and an int representing nanosecond-of-second, which will always be between 0 and 999,999,999.

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

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

There are a variety of gettermethods such as getSeconds, getNano, and get(TemporalUnit). Given that a duration is represented as a (seconds, nanos) pair, it's clear why get(TemporalUnit)is restricted to seconds and nanos. These getter methods extract data directly from the duration instance and are lossless.

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

By contrast, there is a variety of to-methods including toDays, toHours, toMillistoMinutes, and toNanosthat do conversionon the duration value. These conversions are lossy in that they involve truncation of data, or they might throw an exception if the duration value cannot be represented in the requested format.

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

It's clearly part of the design that the get-methods extract data without conversion and the to-methods perform conversions of some sort.

很明显,get-methods 在没有转换的情况下提取数据,to-methods 执行某种类型的转换,这显然是设计的一部分。

回答by Adir D

By below code i got this duration output:

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

1 day, 2 hours, 5 minutes

1天2小时5分钟

code example:

代码示例:

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();
}

Explanation:

说明

By using Duration interface you can easily find the exact String display you want. you just need to reduce the bigger TemporalUnit from current duration.

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

for example:

例如:

  1. calculate days
  2. reduce days from duration
  3. calculate hours
  4. reduce hours from duration etc... until u get duration = 0
  1. 计算天数
  2. 从持续时间减少天数
  3. 计算小时数
  4. 从持续时间等减少小时数...直到你得到持续时间 = 0

回答by Adir D

Remove Hourse then get minutes

删除Hourse然后获得分钟

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

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