0

我想将 Instant / LocalDateTime 舍入到 Java 中最接近的 5 分钟间隔。

示例: 假设时间为: 2021-02-08T19 : 02 :49.594 预期结果: 2021-02-08T19 : 00 :00.000

假设时间是: 2021-02-08T19 : 03 :49.594 预期结果: 2021-02-08T19 : 05 :00.000

同样,如果时间是: 2021-02-08T19 : 56 :49.594 预期结果: 2021-02-08T19 : 55 :00.000

同样,如果时间是: 2021-02-08T19 : 58 :49.594 预期结果: 2021-02-08T20 : 00 :00.000

但是,如果时间是 2021-02-08T19: 55 :00.000 或 2021-02-08T19: 05 :00.000 或 2021-02-08T19: 00 :00.000 则什么也不做。

4

3 回答 3

2

这是一个通用解决方案(不仅仅是 5 分钟):

public static Instant toNearest(Duration interval, Instant instant) {
    long intervalMillis = interval.toMillis();
    long adjustedInstantMillis = (instant.toEpochMilli() + (intervalMillis / 2)) / intervalMillis * intervalMillis;
    return Instant.ofEpochMilli(adjustedInstantMillis);
}

public static LocalDateTime toNearest(Duration interval, LocalDateTime dateTime, ZoneId zoneId) {
    ZoneRules zoneRules = zoneId.getRules();
    Instant instant = toNearest(interval, dateTime.toInstant(zoneRules.getOffset(dateTime)));
    return LocalDateTime.ofInstant(instant, zoneRules.getOffset(instant));
}

public static LocalDateTime toNearest(Duration interval, LocalDateTime dateTime) {
    return toNearest(interval, dateTime, ZoneId.systemDefault());
}

@Test
public void toNearestRoundsCorrectly() {
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 0, 0)))
            .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 0, 0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 2, 29, 999999999)))
            .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 0, 0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 2, 30)))
            .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 5, 0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 5, 0)))
            .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 5, 0));
}

@Test
public void toNearestTreatsDaylightSavingChangesCorrectly() {
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,27, 23,57,30), ZoneId.of("Europe/London")))
            .isEqualTo(LocalDateTime.of(2021,3,28, 0,0,0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 0,57,29,999999999), ZoneId.of("Europe/London")))
            .isEqualTo(LocalDateTime.of(2021,3,28, 0,55,0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 0,57,30), ZoneId.of("Europe/London")))
            .isEqualTo(LocalDateTime.of(2021,3,28, 2,0,0));
    assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 2,5,0), ZoneId.of("Europe/London")))
            .isEqualTo(LocalDateTime.of(2021,3,28, 2,5,0));
}
于 2021-02-12T10:14:59.703 回答
0

这应该相应地四舍五入:

        long min5 = 1000 * 60 * 5;
        String time = "2021-02-08T19:56:49.594";
        time = time.replace("T", " "); // cannot deal with T
        SimpleDateFormat format = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSS");
        try{
            Date dt = format.parse(time);
            long t = dt.getTime();
            long d = t %min5;
            if(d > min5/2) { // round up
                t += min5 - d;
            } else { // round down
                t -= d;
            }
            System.out.println(format.format(new Date(t)));
        }catch(ParseException e){
            e.printStackTrace();
        }
于 2021-02-12T09:57:11.090 回答
0

此代码提供了 Instant 和 LocalDatetime 的示例。

        Instant instant = Instant.now();
        long instantLong = instant.toEpochMilli();
        long roundedEpochMilli = (instantLong/(60*5*1000) )  * 60 * 5 *1000; 
        if((instantLong % (60*5*1000))> (30*5*1000))
             roundedEpochMill += 60*5*1000;
        Instant instantRounded = Instant.ofEpochMilli(roundedEpochMilli);
        System.out.println("instant "+ instant +" -- "+ instantRounded);
        
        LocalDateTime now = LocalDateTime.now();
        ZoneId systemZone = ZoneId.systemDefault(); // my timezone
        ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);
        long nowLong = now.toEpochSecond(currentOffsetForMyZone);
        long roundedEpochSecond = (nowLong/(60*5) )  * 60 * 5; 
        if((nowLong % (60*5))> (30*5))
             roundedEpochSecond += 60*5;
        LocalDateTime nowRounded = LocalDateTime.ofEpochSecond(roundedEpochSecond, 0, currentOffsetForMyZone);
        System.out.println("now "+ instant +" -- "+ nowRounded);
于 2021-02-12T09:53:33.350 回答