乔达持续时间转换为最近的ceil

Joda Duration convert to nearest ceil

我正在使用 Joda-Time Duration 来获取两个 DateTime:

之间的持续时间
DateTime startTimeDate = new DateTime(startTimeDateInLong, DateTimeZone.UTC);
DateTime endTimeDate = new DateTime(endTimeDateInLong, DateTimeZone.UTC);

Duration duration = new Duration(startTimeDate, endTimeDate);

我想按照以下规则转换:

0-60 seconds --> 1 minute ..
1.5 - 1 hour --> 1 hour
1.6 hour - 2 hour --> 2 hour

我正在使用 duration.toStandardHours(),但是 96 分钟它给了 1 小时,而不是我想要 2 小时。

Duration class 没有按照您想要的方式对值进行四舍五入。即使您得到 1 小时 59 分 59 秒 999 毫秒的持续时间,toStandardHours() 也会 return 1.

要得到你想要的结果,你必须得到以秒为单位的总数,然后相应地操作这个值。您可以使用 java.math.BigDecimal class 和 java.math.RoundingMode 来控制值的舍入方式:

// 96-minutes duration
Duration duration = new Duration(96 * 60 * 1000);
long secs = duration.toStandardSeconds().getSeconds();
if (secs >= 3600) { // more than 1 hour
    BigDecimal secondsPerHour = new BigDecimal(3600);
    int hours = new BigDecimal(secs).divide(secondsPerHour, RoundingMode.HALF_DOWN).intValue();

    System.out.println(hours + " hour" + (hours > 1 ? "s" : "")); // 2 hours
} else {
    int mins;
    if (secs == 0) { // round zero seconds to 1 minute
        mins = 1;
    } else {
        // always round up (1-59 seconds = 1 minute)
        BigDecimal secondsPerMin = new BigDecimal(60);
        mins = new BigDecimal(secs).divide(secondsPerMin, RoundingMode.UP).intValue();
    }
    System.out.println(mins + " minute" + (mins > 1 ? "s" : ""));
}

这将打印 2 hours 持续 96 分钟,1 minute 持续 0 到 60 秒,依此类推。

要获得以秒为单位的差异,您还可以使用 org.joda.time.Seconds class:

long secs = Seconds.secondsBetween(startTimeDate, endTimeDate).getSeconds();

Java 新 Date/Time API

Joda-Time 处于维护模式,正在被新的 APIs 取代,所以我不建议用它开始一个新项目。即使在 joda's website 它说:"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".

如果您不能(或不想)从 Joda-Time 迁移到新的 API,您可以忽略此部分。

如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.

如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it ).

下面的代码适用于两者。 唯一的区别是包名称(在 Java 8 中是 java.time,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但是 classes和方法names是一样的。

首先,要从纪元毫秒值中获取对应的时刻,可以使用Instant class(无需将时区设置为UTC,因为Instant代表一个UTC立即的)。然后,要计算差异,您可以使用 Duration:

long startTimeDateInLong = // long millis value
long endTimeDateInLong = // long millis value

// get the corresponding Instant
Instant start = Instant.ofEpochMilli(startTimeDateInLong);
Instant end = Instant.ofEpochMilli(endTimeDateInLong);

// get the difference in seconds
Duration duration = Duration.between(start, end);
long secs = duration.getSeconds();

// perform the same calculations as above (with BigDecimal)

您还可以使用 ChronoUnit 来计算秒数的差异:

long secs = ChronoUnit.SECONDS.between(start, end);

我能找到的唯一方法是先以较小的单位获取时间,然后转换为所需的单位并对其进行舍入。因此,例如,对于提到的用例,获得四舍五入分钟的方法是这样的:

public Minutes getRoundedMinutes(DateTime dateTime1, DateTime dateTime2) {
    return Minutes.minutes(
            (int) round((double) secondsBetween(dateTime1, dateTime2).getSeconds() / Minutes.ONE.toStandardSeconds().getSeconds()));
}

@Test
public void should_round_minutes() throws Exception {
    DateTime dateTime1 = new DateTime(2018, 1, 1, 1, 0, 0);
    DateTime dateTime2 = new DateTime(2018, 1, 1, 1, 0, 29);
    DateTime dateTime3 = new DateTime(2018, 1, 1, 1, 0, 30);
    DateTime dateTime4 = new DateTime(2018, 1, 1, 1, 1, 1);
    DateTime dateTime5 = new DateTime(2018, 1, 1, 1, 1, 31);

    assertThat(getRoundedMinutes(dateTime1, dateTime2).getMinutes()).isEqualTo(0);
    assertThat(getRoundedMinutes(dateTime1, dateTime3).getMinutes()).isEqualTo(1);
    assertThat(getRoundedMinutes(dateTime1, dateTime4).getMinutes()).isEqualTo(1);
    assertThat(getRoundedMinutes(dateTime1, dateTime5).getMinutes()).isEqualTo(2);
}