有没有相当于ChronoUnit.between返回分数而不是整数?

时间:2016-06-13 09:09:32

标签: java java-8 java-time jsr310

这样的方法是ChronoUnit.HOURS.between(start, end)返回long,所以我无法从那里得到分数。

是否有可以返回分数的替代方法/方法?

2 个答案:

答案 0 :(得分:7)

ChronoUnit.HOURS.between(start, end)的重点是获得两个时间点之间的HOURS数量。例如:它之间是1或2小时,没有1.5658小时*。如果您需要更多精确度,请使用另一个ChronoUnit,即分钟或秒。

小数分数的问题是,它们通常基于10,而时间单位是基于圆(360°,2pi等)的分数,它们以整数的分数表示,如1/4,1 / 8,1 / 2等,而不是浮点值。这里的关键字是“浮点”,你可以通过移动点来表示一个值,或者乘以一个10的幂的基值,并使用前缀到单位(即1.5 * 10 ^ 3 == 1500000 * 10 ^ -3 ,其中10 ^ 3是千,10 ^ -3是毫安),但你不能用天,小时,分钟和秒来做。没有千小时或毫天这样的东西,你不能简单地将小时数转换成10分钟的功率。

在现实生活中,没有人会说“这是1小时和8.3%”或“6.5小时后” - 因为这通常会导致混乱(6.30对比6:30) - 因此说“它是1小时5分钟”更实际“或”5过去x“或”四分之一到x“。

因此,在时间API *中进行小数分数计算没有实际用途。但是如果您需要它(即出于计算目的),您可以非常简单地计算它。

如果您需要分数 - 即分钟或秒 - 您必须使用相应的ChronoUnit,即ChronoUnit.MINUTESChronoUnit.SECONDS,并将其除以所需的时间单位整个你想要的一小部分。例如

  • 60分钟一小时
  • 3600秒制作一小时
  • 3600000毫秒制作一小时等。
  • 60秒制作一分钟
  • ...

您可以使用简单的数学计算分数精度,即

double fracH = (double)ChronoUnit.MINUTES.between(start,end) / 60;

作为替代方案,您也可以使用提供Duration方法的between。持续时间可以很容易地转换为分钟,小时等。

Duration dur = Duration.between(start, end);
double fracH = (double)dur.toMinutes() / 60;

要获得最高精度,您必须计算最小时间单位的分数,即nanos或millis

double fracHns = (double)dur.toNanos() / 3_600_000_000_000;

您甚至可以使用Duration获取基数(100%)值:

//fraction of an hour
double fracHns = (double)dur.toNanos() / Duration.ofHours(1).toNanos();

//fraction of a minute
double fracMns = (double)dur.toNanos() / Duration.ofMinutes(1).toNanos();

或者更一般,David SN posted

TemporalUnit unit = ChronoUnit.HOURS;
double frac = (double)Duration.between(start, end).toNanos() 
              / Duration.of(1, unit).toNanos();

*)没有例外的规则:为了使事情变得困难,对于时间单位,计算基数会在小于1秒的单位时发生变化,因为它会从10开始,即毫秒(1/1000),微秒(1 / 1000000th),...因此,对于秒和更小,通常使用小数分数,例如:1.74秒,因为通过简单地移动小数分隔符将其转换为下一个较小的时间单位很简单:

1.74 s <-> 1740.0 ms. 

但是数小时并不容易:

1.74 hours <-> 104.40 minutes.

答案 1 :(得分:2)

ChronoUnit中没有方法可以获得给定时间单位中时差的十进制值。

您可以创建实用程序方法来实现此功能。类Duration可用于此目的。这可以通过获得最小单位的差异并将其(带小数)转换回所需单位来完成:

public static double between(Temporal startInclusive, Temporal endExclusive, ChronoUnit unit) {
    Duration duration = Duration.between(startInclusive, endExclusive);
    long conversion = Duration.of(1, unit).toNanos();
    return (double) duration.toNanos() / conversion;
}