Java 8 LocalDateTime舍入到下一个X分钟

Kin*_*han 6 math datetime date java-8 java-time

我想将Java 8 LocalDateTime转换为最接近的5分钟.例如

1601  ->  1605
1602  ->  1605
1603  ->  1605
1604  ->  1605
1605  ->  1605
1606  ->  1610
1607  ->  1610
1608  ->  1610
1609  ->  1610
1610  ->  1610
Run Code Online (Sandbox Code Playgroud)

我想使用LocalDateTime或Math api的现有功能.有什么建议?

Hol*_*ger 12

您可以使用以下方法向下一个五分钟的舍入:

LocalDateTime dt = …
dt = dt.withSecond(0).withNano(0).plusMinutes((65-dt.getMinute())%5);
Run Code Online (Sandbox Code Playgroud)

您可以使用重现您的示例

LocalDateTime dt=LocalDateTime.now().withHour(16).withSecond(0).withNano(0);
for(int i=1; i<=10; i++) {
    dt=dt.withMinute(i);
    System.out.printf("%02d%02d -> ", dt.getHour(), dt.getMinute());
    // the rounding step:
    dt=dt.plusMinutes((65-dt.getMinute())%5);
    System.out.printf("%02d%02d%n", dt.getHour(), dt.getMinute());
}
Run Code Online (Sandbox Code Playgroud)

1601 -> 1605
1602 -> 1605
1603 -> 1605
1604 -> 1605
1605 -> 1605
1606 -> 1610
1607 -> 1610
1608 -> 1610
1609 -> 1610
1610 -> 1610
Run Code Online (Sandbox Code Playgroud)

(在这个例子中,我只清除秒和纳米一次,因为它们保持为零).

  • 逻辑是`(5-x)mod 5`,但是当值为负时,模运算符`%`并没有执行我们想要的操作,因此此代码改用`(65-x)%5`,因此,因为x总是在0..59之间,所以%左侧的值总是正数,而(65-x)%5 ==(65-x)mod 5。 (2认同)

ass*_*ias 6

作为Holger建议的替代方案,您可以创建一个TemporalAdjuster,这将允许您编写如下内容date.with(nextOrSameMinutes(5)):

public static void main(String[] args) {
  for (int i = 0; i <= 10; i++) {
    LocalDateTime d = LocalDateTime.of(LocalDate.now(), LocalTime.of(16, i, 0));
    LocalDateTime nearest5 = d.with(nextOrSameMinutes(5));
    System.out.println(d.toLocalTime() + " -> " + nearest5.toLocalTime());
  }
}

public static TemporalAdjuster nextOrSameMinutes(int minutes) {
  return temporal -> {
    int minute = temporal.get(ChronoField.MINUTE_OF_HOUR);
    int nearestMinute = (int) Math.ceil(minute / 5d) * 5;
    int adjustBy = nearestMinute - minute;
    return temporal.plus(adjustBy, ChronoUnit.MINUTES);
  };
}
Run Code Online (Sandbox Code Playgroud)

请注意,这不会截断原始日期的秒数/纳米数.如果你想要,你可以修改调整器的结尾:

if (adjustBy == 0
        && (temporal.get(ChronoField.SECOND_OF_MINUTE) > 0 || temporal.get(ChronoField.NANO_OF_SECOND) > 0)) {
  adjustBy += 5;
}
return temporal.plus(adjustBy, ChronoUnit.MINUTES)
          .with(ChronoField.SECOND_OF_MINUTE, 0)
          .with(ChronoField.NANO_OF_SECOND, 0);
Run Code Online (Sandbox Code Playgroud)

  • 这就是 API 的伟大之处,你可以随时将 `foo.bar()` 替换为 `foo.with(f -&gt; f.bar())` 或 `foo.with(Foo::bar)`... (2认同)
  • @Holger lambdas和方法引用的可用性非常好,是的我同意,但也有一个黑暗的一面.与`Collection`-和`Stream`-API相比,`TemporalAdjuster`不是类型安全的.如果您尝试在"Instant"上应用此调整器(例如),那么编译器会说好,但是在运行时会出现异常. (2认同)