计算到目前为止每 15 分钟时间块的成本

Calculate a cost for every 15-minute chunk of time elapsed so far

我希望用户能够了解应用程序使用时间的最新费用。到目前为止,每经过 15 分钟的时间块都按 10 个货币单位定价。

我只关心流逝的时间。与小时的刻度对齐(0-15、15-30、30-45、45-0 分钟)不是目标。

例如,一开始,成本是0个单位。五分钟后,还是0个单位。 17 分钟后,20 个单位是当前成本(10 个货币单位 * 单个 15 分钟时间块完成)。 33 分钟后,当前成本为 20 个单位,因为到目前为止已经过去了 2 个 15 分钟的块。

最后一个小于 15 分钟的当前时间段将被忽略。没有pro rata

tl;博士

Duration                       // Represent a span-of-time not attached to the timeline. Internally, this class stores a number of whole seconds plus a fractional second as a count of nanoseconds.
.between(                      // Calculate elapsed time. 
    start ,                    // Starting moment captured a while ago using `Instant.now()` call.
    Instant.now()              // Capture the current moment.
)                              // Returns a `Duration` object.
.dividedBy(                    // Get whole number (ignoring remainder) of number of 15-minute chunks occurred within that previous `Duration`. 
    Duration.ofMinutes( 15 )   // Another `Duration` object, our 15-minute chunk definition.
)                              // Returns a `long`, a 64-bit integer.
*                              // Multiply our number of chunks of 15-minutes by the price-per-chunk.
price

详情

仅使用 java.time packages, defined in JSR 310 中的 class。避免糟糕的遗留日期时间 classes (Date, Calendar)。

捕捉开始的瞬间。使用 Instant class, to represent a moment in UTC, with a resolution as fine as nanoseconds

Instant start = Instant.now() ;  

编写一个方法来计算您的已用时间成本。在这个方法中:

  • 首先我们得到经过的时间,即从开始时刻到当前时刻的时间量。我们在 UTC 中执行此操作,因为涉及时区没有任何好处。我们将经过的时间表示为 Duration.
  • 其次,我们计算经过时间的已完成块。我们再次使用 Duration class 定义要收费的时间段,15 分钟。然后我们调用 Duration::dividedBy 来获取已完成块的计数。
  • 第三,我们通过将单价乘以经过的时间块的总数来计算成本。如果您使用小数表示货币,例如美元或加元,而不是整数,请使用 BigDecimal 而不是 Integer。搜索 Stack Overflow 以获取更多信息,因为这已经被讨论过很多次了。

注意使用 Math.toIntExact 将 64 位 long 截断为 32 位 int,但如果发生溢出则抛出异常。

代码。

public Integer calculateCostForElapsedTimeSoFar ( final Instant start , final Integer price )
{
    // Determine elapsed time.
    Instant now = Instant.now();
    Duration elapsed = Duration.between( start , now );

    // See how many chunks of 15 minutes have occurred.
    Duration chunk = Duration.ofMinutes( 15 ); // Charge for every chunk of time in chunks of 15 minutes. You could make this a constant instead of a local variable.
    int chunks = Math.toIntExact( elapsed.dividedBy( chunk ) );   // Returns number of whole times a specified Duration occurs within this Duration.

    // Calculate charges.
    Integer cost = ( price * chunks );
    return cost;
}

用法示例。

final Instant start = Instant.now().minus( Duration.ofMinutes( 21 ) );
final Integer price = 10;   // This may come from some other place, such as a look-up in a database.
Integer cost = this.calculateCostForElapsedTimeSoFar( start , price );
System.out.println( "cost: " + cost );

看到这个 code run live at IdeOne.com

cost: 10

如果您想自动更新当前成本的显示,而无需用户执行诸如单击按钮之类的操作,请了解 Executors framework built into Java. Specifically, see the ScheduledExecutorService. And learn about how to asynchronously updating the widgets within your particular user-interface framework (Vaadin, JavaFX, Swing 等)。同样,搜索 Stack Overflow 以获取更多信息,因为这两个主题已经被多次提及。

如果您担心主机上的时钟被重置,请参阅替代方法 approach by user2023577